diff --git a/examples/.gitignore b/examples/.gitignore index 7b698948d..6b96607c5 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -28,3 +28,4 @@ dramsim3.txt *.d *.dis *.diso +lfs.c diff --git a/examples/spmd/icache_miss_bombing/Makefile b/examples/spmd/icache_miss_bombing/Makefile new file mode 100644 index 000000000..1bf4b4b32 --- /dev/null +++ b/examples/spmd/icache_miss_bombing/Makefile @@ -0,0 +1,51 @@ +# Copyright (c) 2021, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile compiles, links, and executes examples Run `make help` +# to see the available targets for the selected platform. + +################################################################################ +# environment.mk verifies the build environment and sets the following +# makefile variables: +# +# LIBRAIRES_PATH: The path to the libraries directory +# HARDWARE_PATH: The path to the hardware directory +# EXAMPLES_PATH: The path to the examples directory +# BASEJUMP_STL_DIR: Path to a clone of BaseJump STL +# BSG_MANYCORE_DIR: Path to a clone of BSG Manycore +############################################################################### + +REPLICANT_PATH:=$(shell git rev-parse --show-toplevel) + +# Name of the SPMD test. In this case, the name of the directory +SPMD_NAME := $(notdir $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))) + +include $(REPLICANT_PATH)/environment.mk + +SPMD_SRC_PATH = $(BSG_MANYCORE_DIR)/software/spmd + +include $(EXAMPLES_PATH)/spmd/loader.mk diff --git a/hardware/hardware.mk b/hardware/hardware.mk index d6db059be..cf4304cfc 100644 --- a/hardware/hardware.mk +++ b/hardware/hardware.mk @@ -175,6 +175,7 @@ $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.rom: $(BSG_MACHINE_PATH)/Makef @echo $(call dec2bin,$(BSG_MACHINE_IO_EP_CREDITS)) >> $@.temp @echo $(call dec2bin,0) >> $@.temp @echo $(call hex2bin,$(CHIP_ID)) >> $@.temp + @echo $(call dec2bin,$(BSG_MACHINE_HOST_TYPE)) >> $@.temp @cat $(BSG_MACHINE_PATH)/bsg_bladerunner_memsys.rom >> $@.temp mv $@.temp $@ diff --git a/libraries/.gitignore b/libraries/.gitignore index 8b447aa5d..0f96f095f 100644 --- a/libraries/.gitignore +++ b/libraries/.gitignore @@ -1,4 +1,5 @@ *.o *.so *.so.1 -*.so.1.0 \ No newline at end of file +*.so.1.0 +*.a diff --git a/libraries/bsg_manycore_config.cpp b/libraries/bsg_manycore_config.cpp index b7298eca3..d2f391045 100644 --- a/libraries/bsg_manycore_config.cpp +++ b/libraries/bsg_manycore_config.cpp @@ -193,6 +193,11 @@ int hb_mc_config_init(const hb_mc_config_raw_t raw[HB_MC_CONFIG_MAX], CHECK_FIELD(HB_MC_CONFIG_IO_HOST_CREDITS_CAP, idx >= HB_MC_HOST_CREDITS_MIN && idx <= HB_MC_HOST_CREDITS_MAX); config->io_host_credits_cap = idx; + // Host type + idx = raw[HB_MC_CONFIG_HOST_TYPE]; + CHECK_FIELD(HB_MC_CONFIG_HOST_TYPE, idx >= HB_MC_HOST_TYPE_PC && idx <= HB_MC_HOST_TYPE_BLACKPARROT); + config->host_type = idx; + err = hb_mc_memsys_init(&raw[HB_MC_CONFIG_MEMSYS], &config->memsys); if (err != HB_MC_SUCCESS) { bsg_pr_err("%s: Failed to initialize memory system: %s\n", diff --git a/libraries/bsg_manycore_config.h b/libraries/bsg_manycore_config.h index 0956dfaa4..db2b5814f 100644 --- a/libraries/bsg_manycore_config.h +++ b/libraries/bsg_manycore_config.h @@ -65,6 +65,10 @@ extern "C" { #define HB_MC_HOST_CREDITS_MIN 1 #define HB_MC_HOST_CREDITS_MAX 32 + // PC is off-die x86/ARM, BlackParrot is on-die host + #define HB_MC_HOST_TYPE_PC 0 + #define HB_MC_HOST_TYPE_BLACKPARROT 1 + typedef hb_mc_rom_word_t hb_mc_config_raw_t; /* Compilation Metadata */ @@ -108,6 +112,7 @@ extern "C" { uint32_t io_host_credits_cap; uint32_t io_endpoint_max_out_credits; uint32_t chip_id; + uint32_t host_type; hb_mc_memsys_t memsys; } hb_mc_config_t; @@ -142,7 +147,8 @@ extern "C" { HB_MC_CONFIG_IO_HOST_CREDITS_CAP = 26, HB_MC_CONFIG_IO_EP_MAX_OUT_CREDITS = 27, HB_MC_CONFIG_CHIP_ID = 28, - HB_MC_CONFIG_MEMSYS = 29, + HB_MC_CONFIG_HOST_TYPE = 29, + HB_MC_CONFIG_MEMSYS = 30, HB_MC_CONFIG_MAX=HB_MC_CONFIG_MEMSYS + HB_MC_MEMSYS_ROM_IDX_MAX, } hb_mc_config_id_t; diff --git a/libraries/bsg_manycore_cuda.cpp b/libraries/bsg_manycore_cuda.cpp index 69ff7f4eb..f1a2e0df4 100644 --- a/libraries/bsg_manycore_cuda.cpp +++ b/libraries/bsg_manycore_cuda.cpp @@ -2105,12 +2105,14 @@ int hb_mc_device_pod_dma_to_device(hb_mc_device_t *device, hb_mc_pod_id_t pod_id hb_mc_pod_t *pod = &device->pods[pod_id]; // flush cache - err = hb_mc_manycore_pod_flush_vcache(device->mc, pod->pod_coord); - if (err != HB_MC_SUCCESS) { - bsg_pr_err("%s: failed to flush victim cache: %s\n", - __func__, - hb_mc_strerror(err)); - return err; + if (device->mc->config.host_type == HB_MC_HOST_TYPE_PC) { + err = hb_mc_manycore_pod_flush_vcache(device->mc, pod->pod_coord); + if (err != HB_MC_SUCCESS) { + bsg_pr_err("%s: failed to flush victim cache: %s\n", + __func__, + hb_mc_strerror(err)); + return err; + } } // for each job... @@ -2136,9 +2138,11 @@ int hb_mc_device_pod_dma_to_device(hb_mc_device_t *device, hb_mc_pod_id_t pod_id } // invalidate cache - err = hb_mc_manycore_pod_invalidate_vcache(device->mc, pod->pod_coord); - if (err != HB_MC_SUCCESS) { - return err; + if (device->mc->config.host_type == HB_MC_HOST_TYPE_PC) { + err = hb_mc_manycore_pod_invalidate_vcache(device->mc, pod->pod_coord); + if (err != HB_MC_SUCCESS) { + return err; + } } return HB_MC_SUCCESS; @@ -2155,12 +2159,14 @@ int hb_mc_device_pod_dma_to_host(hb_mc_device_t *device, hb_mc_pod_id_t pod_id, // flush cache hb_mc_pod_t *pod = &device->pods[pod_id]; - err = hb_mc_manycore_pod_flush_vcache(device->mc, pod->pod_coord); - if (err != HB_MC_SUCCESS) { - bsg_pr_err("%s: failed to flush victim cache: %s\n", - __func__, - hb_mc_strerror(err)); - return err; + if (device->mc->config.host_type == 0) { + err = hb_mc_manycore_pod_flush_vcache(device->mc, pod->pod_coord); + if (err != HB_MC_SUCCESS) { + bsg_pr_err("%s: failed to flush victim cache: %s\n", + __func__, + hb_mc_strerror(err)); + return err; + } } // for each job... diff --git a/libraries/bsg_manycore_memsys.h b/libraries/bsg_manycore_memsys.h index ff7038c73..4833bf7f7 100644 --- a/libraries/bsg_manycore_memsys.h +++ b/libraries/bsg_manycore_memsys.h @@ -63,6 +63,7 @@ typedef struct __hb_mc_memsys_t { // memory system features uint32_t feature_dma; //!< Can I do DMA? uint32_t feature_cache; //!< Do I have DMA? + uint32_t dma2cache; //!< Does my DMA write directly to vcache // dram address bitfields hb_mc_dram_pa_bitfield dram_ro; //!< DRAM row bits info hb_mc_dram_pa_bitfield dram_bg; //!< DRAM bankgroup bits info diff --git a/libraries/bsg_manycore_packet.h b/libraries/bsg_manycore_packet.h index f147918e2..74219f714 100644 --- a/libraries/bsg_manycore_packet.h +++ b/libraries/bsg_manycore_packet.h @@ -40,7 +40,7 @@ extern "C" { hb_mc_request_packet_t request; /**/ hb_mc_response_packet_t response; /* from the Hammerblade Manycore */ uint32_t words[4]; - } __attribute__((aligned(4))) hb_mc_packet_t; + } __attribute__((aligned(8))) hb_mc_packet_t; /** * Fill a response packet fields using a request packet. diff --git a/libraries/bsg_manycore_request_packet.h b/libraries/bsg_manycore_request_packet.h index 396e486b1..f7e6ffa46 100644 --- a/libraries/bsg_manycore_request_packet.h +++ b/libraries/bsg_manycore_request_packet.h @@ -75,7 +75,7 @@ extern "C" { uint8_t op_v2; //!< opcode uint32_t addr; //!< address field (EPA) uint8_t reserved[2]; - } __attribute__((packed, aligned(4))) hb_mc_request_packet_t; + } __attribute__((packed, aligned(8))) hb_mc_request_packet_t; typedef struct hb_mc_request_packet_load_info { uint32_t part_sel; diff --git a/libraries/bsg_manycore_response_packet.h b/libraries/bsg_manycore_response_packet.h index c9a4c784d..7f19994a8 100644 --- a/libraries/bsg_manycore_response_packet.h +++ b/libraries/bsg_manycore_response_packet.h @@ -51,7 +51,7 @@ extern "C" { uint32_t data; //!< packet's payload data uint8_t op; //!< opcode uint8_t reserved[8]; - } __attribute__((packed, aligned(4))) hb_mc_response_packet_t; + } __attribute__((packed, aligned(8))) hb_mc_response_packet_t; /** diff --git a/libraries/features/dma/blackparrot/bsg_manycore_dma.cpp b/libraries/features/dma/blackparrot/bsg_manycore_dma.cpp new file mode 100644 index 000000000..566a007eb --- /dev/null +++ b/libraries/features/dma/blackparrot/bsg_manycore_dma.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include + +/* these are convenience macros that are only good for one line prints */ +#define dma_pr_dbg(mc, fmt, ...) \ + bsg_pr_dbg("%s: " fmt, mc->name, ##__VA_ARGS__) + +#define dma_pr_err(mc, fmt, ...) \ + bsg_pr_err("%s: " fmt, mc->name, ##__VA_ARGS__) + +#define dma_pr_warn(mc, fmt, ...) \ + bsg_pr_warn("%s: " fmt, mc->name, ##__VA_ARGS__) + +#define dma_pr_info(mc, fmt, ...) \ + bsg_pr_info("%s: " fmt, mc->name, ##__VA_ARGS__) + +int hb_mc_npa_to_bp_eva(hb_mc_manycore_t *mc, + const hb_mc_npa_t *npa, + uint64_t *bp_eva) { + const hb_mc_config_t *cfg = hb_mc_manycore_get_config(mc); + hb_mc_coordinate_t coord = hb_mc_npa_get_xy(npa); + hb_mc_coordinate_t npod = hb_mc_config_npod(cfg, coord); + unsigned long long npody2 = npod.y / 2; // We pack all vcache pods into 2 + hb_mc_epa_t epa = hb_mc_npa_get_epa(npa); + + uint64_t base_eva; + if (hb_mc_config_is_vanilla_core(cfg, coord)) { + *bp_eva = 0 + | (3ULL << 38ULL) + | (coord.y << 25ULL) + | (coord.x << 18ULL) + | (epa << 0ULL); + } else if (hb_mc_config_is_dram(cfg, coord)) { + *bp_eva = 0 + | (2ULL << 38ULL) + | (npody2 << 36ULL) + | (coord.x << 29ULL) + | (epa << 0ULL); + } else { + dma_pr_err(mc, "%s: DMA region not supported on this platform\n", __func__); + return HB_MC_NOIMPL; + } + + return HB_MC_SUCCESS; +} + +/** + * Write memory out to manycore DRAM via DMA + * + * NOTE: This method is declared with __attribute__((weak)) so that a + * platform can define write OR read in its own bsg_manycore_dma.cpp + * implementation, but does not need to declare both. + * + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] npa A valid hb_mc_npa_t - must be an L2 cache coordinate + * @param[in] data A buffer to be written out manycore hardware + * @param[in] sz The number of bytes to write to manycore hardware + * @return HB_MC_FAIL if an error occured. HB_MC_SUCCESS otherwise. + */ +int hb_mc_dma_write(hb_mc_manycore_t *mc, + const hb_mc_npa_t *npa, + const void *data, size_t sz) +{ + int rc; + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + uint64_t base_eva; + if ((rc = hb_mc_npa_to_bp_eva(mc, npa, &base_eva)) != HB_MC_SUCCESS) { + return rc; + } + + int32_t *buf = (int32_t *) data; + for (int i = 0; i < sz; i+=4) { + uint64_t bp_eva = base_eva + i; + if ((rc = mcl->mmio_write(bp_eva, buf[i/4], 0xf)) != HB_MC_SUCCESS) { + return rc; + } + } + + return HB_MC_SUCCESS; +} + + +/** + * Read memory from manycore DRAM via DMA + * + * NOTE: This method is declared with __attribute__((weak)) so that a + * platform can define write OR read in its own bsg_manycore_dma.cpp + * implementation, but does not need to declare both. + * + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] npa A valid hb_mc_npa_t - must be an L2 cache coordinate + * @param[in] data A host buffer to be read into from manycore hardware + * @param[in] sz The number of bytes to read from manycore hardware + * @return HB_MC_FAIL if an error occured. HB_MC_SUCCESS otherwise. + */ +int hb_mc_dma_read(hb_mc_manycore_t *mc, + const hb_mc_npa_t *npa, + void *data, size_t sz) +{ + int rc; + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + uint64_t base_eva; + if ((rc = hb_mc_npa_to_bp_eva(mc, npa, &base_eva)) != HB_MC_SUCCESS) { + return rc; + } + + int32_t *buf = (int32_t *) data; + for (int i = 0; i < sz; i+=4) { + uint64_t bp_eva = base_eva + i; + if ((rc = mcl->mmio_read(bp_eva, &buf[i/4])) != HB_MC_SUCCESS) { + return rc; + } + } + + return HB_MC_SUCCESS; +} + +int hb_mc_dma_init(hb_mc_manycore_t *mc) +{ + mc->config.memsys.dma2cache = 1; + return HB_MC_SUCCESS; +} + diff --git a/libraries/features/dma/blackparrot/feature.mk b/libraries/features/dma/blackparrot/feature.mk new file mode 100644 index 000000000..2f6239e84 --- /dev/null +++ b/libraries/features/dma/blackparrot/feature.mk @@ -0,0 +1,44 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +DMA_FEATURE_CXXSOURCES += $(LIBRARIES_PATH)/features/dma/blackparrot/bsg_manycore_dma.cpp + +DMA_FEATURE_OBJECTS += $(patsubst %cpp,%o,$(DMA_FEATURE_CXXSOURCES)) +DMA_FEATURE_OBJECTS += $(patsubst %c,%o,$(DMA_FEATURE_CSOURCES)) + +$(DMA_FEATURE_OBJECTS): INCLUDES := -I$(LIBRARIES_PATH) +$(DMA_FEATURE_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/dma +$(DMA_FEATURE_OBJECTS): CFLAGS := -std=c11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(DMA_FEATURE_OBJECTS): CXXFLAGS := -std=c++11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) + +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1.0: $(DMA_FEATURE_OBJECTS) + +.PHONY: dma_feature.clean +dma_feature.clean: + rm -f $(DMA_FEATURE_OBJECTS) + +platform.clean: dma_feature.clean diff --git a/libraries/features/dma/noimpl/feature.mk b/libraries/features/dma/noimpl/feature.mk index 84aa9b7b3..cb90ad1ea 100644 --- a/libraries/features/dma/noimpl/feature.mk +++ b/libraries/features/dma/noimpl/feature.mk @@ -35,8 +35,8 @@ DMA_FEATURE_OBJECTS += $(patsubst %c,%o,$(DMA_FEATURE_CSOURCES)) $(DMA_FEATURE_OBJECTS): INCLUDES := -I$(LIBRARIES_PATH) $(DMA_FEATURE_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/dma -$(DMA_FEATURE_OBJECTS): CFLAGS := -std=c11 -fPIC -D_GNU_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) -$(DMA_FEATURE_OBJECTS): CXXFLAGS := -std=c++11 -fPIC -D_GNU_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(DMA_FEATURE_OBJECTS): CFLAGS := -std=c11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(DMA_FEATURE_OBJECTS): CXXFLAGS := -std=c++11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1.0: $(DMA_FEATURE_OBJECTS) diff --git a/libraries/features/profiler/noimpl/feature.mk b/libraries/features/profiler/noimpl/feature.mk new file mode 100644 index 000000000..1eb7bb4af --- /dev/null +++ b/libraries/features/profiler/noimpl/feature.mk @@ -0,0 +1,47 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# aws-fpga does not provide a DMA feature. Therefore, we compile +# features/profiler/noimpl/bsg_manycore_profiler.cpp that simply returns +# HB_MC_NO_IMPL for each function call. +DMA_FEATURE_CXXSOURCES += $(LIBRARIES_PATH)/features/profiler/noimpl/bsg_manycore_profiler.cpp + +DMA_FEATURE_OBJECTS += $(patsubst %cpp,%o,$(DMA_FEATURE_CXXSOURCES)) +DMA_FEATURE_OBJECTS += $(patsubst %c,%o,$(DMA_FEATURE_CSOURCES)) + +$(DMA_FEATURE_OBJECTS): INCLUDES := -I$(LIBRARIES_PATH) +$(DMA_FEATURE_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/profiler +$(DMA_FEATURE_OBJECTS): CFLAGS := -std=c11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(DMA_FEATURE_OBJECTS): CXXFLAGS := -std=c++11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) + +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1.0: $(DMA_FEATURE_OBJECTS) + +.PHONY: profiler_feature.clean +profiler_feature.clean: + rm -f $(DMA_FEATURE_OBJECTS) + +platform.clean: profiler_feature.clean diff --git a/libraries/features/tracer/noimpl/feature.mk b/libraries/features/tracer/noimpl/feature.mk new file mode 100644 index 000000000..a442ecadf --- /dev/null +++ b/libraries/features/tracer/noimpl/feature.mk @@ -0,0 +1,47 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# aws-fpga does not provide a DMA feature. Therefore, we compile +# features/tracer/noimpl/bsg_manycore_tracer.cpp that simply returns +# HB_MC_NO_IMPL for each function call. +DMA_FEATURE_CXXSOURCES += $(LIBRARIES_PATH)/features/tracer/noimpl/bsg_manycore_tracer.cpp + +DMA_FEATURE_OBJECTS += $(patsubst %cpp,%o,$(DMA_FEATURE_CXXSOURCES)) +DMA_FEATURE_OBJECTS += $(patsubst %c,%o,$(DMA_FEATURE_CSOURCES)) + +$(DMA_FEATURE_OBJECTS): INCLUDES := -I$(LIBRARIES_PATH) +$(DMA_FEATURE_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/tracer +$(DMA_FEATURE_OBJECTS): CFLAGS := -std=c11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(DMA_FEATURE_OBJECTS): CXXFLAGS := -std=c++11 -fPIC -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) + +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1.0: $(DMA_FEATURE_OBJECTS) + +.PHONY: tracer_feature.clean +tracer_feature.clean: + rm -f $(DMA_FEATURE_OBJECTS) + +platform.clean: tracer_feature.clean diff --git a/libraries/libraries.mk b/libraries/libraries.mk index 5f41e8d80..91406992e 100644 --- a/libraries/libraries.mk +++ b/libraries/libraries.mk @@ -115,6 +115,7 @@ $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): INCLUDES $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): INCLUDES += -I$(LIBRARIES_PATH)/features/dma $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): INCLUDES += -I$(LIBRARIES_PATH)/features/profiler $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): INCLUDES += -I$(BSG_PLATFORM_PATH) +$(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): INCLUDES += -I$(BSG_PLATFORM_PATH)/include $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): CFLAGS += -std=c11 -fPIC $(INCLUDES) -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION): CXXFLAGS += -std=c++11 -fPIC $(INCLUDES) -D_GNU_SOURCE -D_BSD_SOURCE -D_DEFAULT_SOURCE @@ -149,11 +150,23 @@ $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so.1.0: LD = $(CXX) $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so.1.0: $(LIB_OBJECTS_REGRESSION) $(LD) -shared -Wl,-soname,$(basename $(notdir $@)) -o $@ $^ $(LDFLAGS) +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.a: $(LIB_OBJECTS) + $(AR) -rc $@ $^ + +$(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.a: $(LIB_OBJECTS_CUDA_POD_REPL) + $(AR) -rc $@ $^ + +$(BSG_PLATFORM_PATH)/libbsg_manycore_regression.a: $(LIB_OBJECTS_REGRESSION) + $(AR) -rc $@ $^ + .PHONY: libraries.clean libraries.clean: rm -f $(LIB_OBJECTS) $(LIB_OBJECTS_CUDA_POD_REPL) $(LIB_OBJECTS_REGRESSION) rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1.0 rm -f $(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.so.1.0 rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so.1.0 + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.a + rm -f $(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.a + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.a endif diff --git a/libraries/platforms/bigblade-vcs/compilation.mk b/libraries/platforms/bigblade-vcs/compilation.mk index 2b64d5912..195103646 100644 --- a/libraries/platforms/bigblade-vcs/compilation.mk +++ b/libraries/platforms/bigblade-vcs/compilation.mk @@ -26,5 +26,4 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. include $(LIBRARIES_PATH)/platforms/common/dpi/compilation.mk -$(PLATFORM_REGRESSION_OBJECTS): INCLUDES += $(LIBRARIES_PATH)/platforms/common/dpi diff --git a/libraries/bsg_manycore_regression_platform.h b/libraries/platforms/common/dpi/bsg_manycore_regression_platform.h similarity index 100% rename from libraries/bsg_manycore_regression_platform.h rename to libraries/platforms/common/dpi/bsg_manycore_regression_platform.h diff --git a/libraries/platforms/common/dpi/hardware.mk b/libraries/platforms/common/dpi/hardware.mk index 4854ad04b..cfb885de0 100644 --- a/libraries/platforms/common/dpi/hardware.mk +++ b/libraries/platforms/common/dpi/hardware.mk @@ -85,6 +85,7 @@ VSOURCES += $(BASEJUMP_STL_DIR)/bsg_misc/bsg_cycle_counter.v # Core Profiler/Trace VSOURCES += $(BSG_MANYCORE_DIR)/testbenches/common/v/vanilla_exe_bubble_classifier_pkg.v +VSOURCES += $(BSG_MANYCORE_DIR)/testbenches/common/v/vanilla_scoreboard_tracker_pkg.v VSOURCES += $(BASEJUMP_STL_DIR)/bsg_test/bsg_nonsynth_dpi_gpio.v VSOURCES += $(BSG_MANYCORE_DIR)/testbenches/common/v/instr_trace.v VSOURCES += $(BSG_MANYCORE_DIR)/testbenches/common/v/vanilla_core_trace.v diff --git a/libraries/platforms/hammerblade-vcs/bsg_manycore_platform.cpp b/libraries/platforms/hammerblade-vcs/bsg_manycore_platform.cpp new file mode 100644 index 000000000..1d634f13d --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/bsg_manycore_platform.cpp @@ -0,0 +1,445 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +///////////////////////////////////////////// +// Header Definitions +///////////////////////////////////////////// + +#include +#include +#include + +///////////////////////////////////////////// +// Globals +///////////////////////////////////////////// + +int bp_mc_link_t::try_write_bp_request_fifo(uint64_t data) +{ + int ctr = *bp_req_fifo_ctr_addr; + + if (ctr == 0) { + return -1; + } + + *bp_req_fifo_data_addr = data; + + return 0; +} + +int bp_mc_link_t::try_write_bp_response_fifo(uint64_t data) +{ + int ctr = *bp_rsp_fifo_ctr_addr; + + *bp_rsp_fifo_data_addr = data; + + return 0; +} + +int bp_mc_link_t::try_read_mc_response_fifo(uint64_t *data) +{ + int ctr = *mc_rsp_fifo_ctr_addr; + + if (ctr == 0) { + return -1; + } + + *data = *mc_rsp_fifo_data_addr; + + return 0; +} + +int bp_mc_link_t::try_read_mc_request_fifo(uint64_t *data) +{ + int ctr = *mc_req_fifo_ctr_addr; + + if (ctr == 0) { + return -1; + } + + *data = *mc_req_fifo_data_addr; + + return 0; +} + +int bp_mc_link_t::tx_fifo_req(hb_mc_request_packet_t *packet) +{ + int packet_len = sizeof(hb_mc_request_packet_t) / 8; + + uint64_t *pkt_data = reinterpret_cast(packet); + + bsg_pr_dbg("Transmit (%x,%x)[%x] <- [%x]\n", packet->y_dst, packet->x_dst, packet->addr, packet->payload); + + int i = 0; + int rc; + while (i < packet_len) { + rc = try_write_bp_request_fifo(pkt_data[i]); + + if (rc == 0) { + i++; + } + } + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::tx_fifo_rsp(hb_mc_response_packet_t *packet) +{ + int packet_len = sizeof(hb_mc_response_packet_t) / 8; + + uint64_t *pkt_data = reinterpret_cast(packet); + + int i = 0; + int rc; + while (i < packet_len) { + rc = try_write_bp_response_fifo(pkt_data[i]); + + if (rc == 0) { + i++; + } + } + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::rx_fifo_req(hb_mc_request_packet_t *packet) +{ + int packet_len = sizeof(hb_mc_request_packet_t) / 8; + + uint64_t *pkt_data = reinterpret_cast(packet); + + int i = 0; + int rc; + while (i < packet_len) { + rc = try_read_mc_request_fifo(&pkt_data[i]); + + if (rc == 0) { + i++; + } + } + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::rx_fifo_rsp(hb_mc_response_packet_t *packet) +{ + int packet_len = sizeof(hb_mc_response_packet_t) / 8; + + uint64_t *pkt_data = reinterpret_cast(packet); + + int i = 0; + int rc; + while (i < packet_len) { + rc = try_read_mc_response_fifo(&pkt_data[i]); + + if (rc == 0) { + i++; + } + } + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::mmio_read(uint64_t address, int32_t *data) { + int32_t *ptr = (int32_t *) address; + + *data = *ptr; + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::mmio_write(uint64_t address, int32_t data, uint8_t mask) { + if (mask != 0xf) { + return HB_MC_INVALID; + } + + int32_t *ptr = (int32_t *) address; + *ptr = data; + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::fifo_fence() { + while (*endpoint_credits_addr > 0); + + return HB_MC_SUCCESS; +} + +int bp_mc_link_t::fifo_drain() { + int unused; + int i = 0; + bsg_pr_info("Draining Request Fifo\n"); + while (*mc_req_fifo_ctr_addr > 0) { + unused = *mc_req_fifo_data_addr; + } + + i = 0; + bsg_pr_info("Draining Response Fifo\n"); + while (*mc_rsp_fifo_ctr_addr > 0) { + unused = *mc_rsp_fifo_data_addr; + } + + return HB_MC_SUCCESS; +} + +///////////////////////////////////////////// +// Convenience Functions +///////////////////////////////////////////// + +///////////////////////////////////////////// +// Platform Functions +///////////////////////////////////////////// + +/** + * Transmit a request packet to manycore hardware + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] request A request packet to transmit to manycore hardware + * @param[in] timeout A timeout counter. Unused - set to -1 to wait forever. + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_transmit(hb_mc_manycore_t *mc, + hb_mc_packet_t *packet, + hb_mc_fifo_tx_t type, + long timeout) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + if (timeout != -1) { + return HB_MC_INVALID; + } + + switch (type) { + case HB_MC_FIFO_TX_REQ: return mcl->tx_fifo_req((hb_mc_request_packet_t *)packet); + case HB_MC_FIFO_TX_RSP: return mcl->tx_fifo_rsp((hb_mc_response_packet_t *)packet); + } + bsg_pr_info("failed to transmit...\n"); + + return HB_MC_NOIMPL; +} + +/** + * Receive a packet from manycore hardware + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] response A packet into which data should be read + * @param[in] timeout A timeout counter. Unused - set to -1 to wait forever. + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_receive(hb_mc_manycore_t *mc, + hb_mc_packet_t *packet, + hb_mc_fifo_rx_t type, + long timeout) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + if (timeout != -1) { + return HB_MC_INVALID; + } + + switch (type) { + case HB_MC_FIFO_RX_REQ: return mcl->rx_fifo_req((hb_mc_request_packet_t *)packet); + case HB_MC_FIFO_RX_RSP: return mcl->rx_fifo_rsp((hb_mc_response_packet_t *)packet); + } + + return HB_MC_NOIMPL; +} + +/** + * Read the configuration register at an index + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] idx Configuration register index to access + * @param[out] config Configuration value at index + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_get_config_at(hb_mc_manycore_t *mc, + unsigned int idx, + hb_mc_config_raw_t *config) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + if (idx < HB_MC_CONFIG_MAX) { + int config_address = hb_mc_config_id_to_addr(HOST_BOOTROM_REG, (hb_mc_config_id_t) idx); + int config_data; + int rc = mcl->mmio_read(config_address, &config_data); + if (rc == HB_MC_SUCCESS) { + *config = config_data; + } + + return rc; + } + + return HB_MC_INVALID; +} + +/** + * Clean up the runtime platform + * @param[in] mc A manycore to clean up + */ +void hb_mc_platform_cleanup(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return; +} + +/** + * Initialize the runtime platform + * @param[in] mc A manycore to initialize + * @param[in] id ID which selects the physical hardware from which this manycore is configured + * @return HB_MC_FAIL if an error occured. HB_MC_NOIMPL otherwise. + */ +int hb_mc_platform_init(hb_mc_manycore_t *mc, + hb_mc_manycore_id_t id) +{ + int err; + bp_mc_link_t *mcl = new bp_mc_link_t; + + if (mc->platform) + return HB_MC_INITIALIZED_TWICE; + + if (id != 0) { + return HB_MC_INVALID; + } + + mc->platform = reinterpret_cast(mcl); + + mcl->fifo_drain(); + + return HB_MC_SUCCESS; +} + + +/** + * Stall until the all requests (and responses) have reached their destination. + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] timeout A timeout counter. Unused - set to -1 to wait forever. + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_fence(hb_mc_manycore_t *mc, + long timeout) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + mcl->fifo_fence(); + + return HB_MC_SUCCESS; +} + +/** + * Signal the hardware to start a bulk transfer over the network + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_start_bulk_transfer(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + +/** + * Signal the hardware to end a bulk transfer over the network + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_finish_bulk_transfer(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + +/** + * Get the current cycle counter of the Manycore Platform + * + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[out] time The current counter value. + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_get_cycle(hb_mc_manycore_t *mc, uint64_t *time) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Get the number of instructions executed for a certain class of instructions + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] itype An enum defining the class of instructions to query. + * @param[out] count The number of instructions executed in the queried class. + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_get_icount(hb_mc_manycore_t *mc, bsg_instr_type_e itype, int *count) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Enable trace file generation (vanilla_operation_trace.csv) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_trace_enable(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Disable trace file generation (vanilla_operation_trace.csv) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_trace_disable(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Enable log file generation (vanilla.log) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_log_enable(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Disable log file generation (vanilla.log) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_log_disable(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Check if chip reset has completed. + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_NOIMPL on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_wait_reset_done(hb_mc_manycore_t *mc) +{ + bp_mc_link_t *mcl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + diff --git a/libraries/platforms/hammerblade-vcs/bsg_manycore_platform.hpp b/libraries/platforms/hammerblade-vcs/bsg_manycore_platform.hpp new file mode 100644 index 000000000..327b7f3c8 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/bsg_manycore_platform.hpp @@ -0,0 +1,39 @@ +#ifndef BSG_MANYCORE_PLATFORM_HPP +#define BSG_MANYCORE_PLATFORM_HPP + +#define HOST_BASE_ADDRESS 0x100000 +#define HOST_PUTCHAR_REG (HOST_BASE_ADDRESS + 0x1000) +#define HOST_GETCHAR_REG (HOST_BASE_ADDRESS + 0x2000) +#define HOST_BOOTROM_REG (HOST_BASE_ADDRESS + 0x3000) + +class bp_mc_link_t { + private: + uint64_t fifo_base_addr = (uint64_t) 0x500000; + volatile uint64_t *bp_req_fifo_data_addr = (volatile uint64_t *) (fifo_base_addr + 0x1000); + volatile int *bp_req_fifo_ctr_addr = (volatile int *) (fifo_base_addr + 0x2000); + volatile uint64_t *mc_rsp_fifo_data_addr = (volatile uint64_t *) (fifo_base_addr + 0x3000); + volatile int *mc_rsp_fifo_ctr_addr = (volatile int *) (fifo_base_addr + 0x4000); + volatile uint64_t *mc_req_fifo_data_addr = (volatile uint64_t *) (fifo_base_addr + 0x5000); + volatile int *mc_req_fifo_ctr_addr = (volatile int *) (fifo_base_addr + 0x6000); + volatile uint64_t *bp_rsp_fifo_data_addr = (volatile uint64_t *) (fifo_base_addr + 0x7000); + volatile int *bp_rsp_fifo_ctr_addr = (volatile int *) (fifo_base_addr + 0x8000); + volatile int *endpoint_credits_addr = (volatile int *) (fifo_base_addr + 0x9000); + + int try_write_bp_request_fifo(uint64_t data); + int try_write_bp_response_fifo(uint64_t data); + int try_read_mc_response_fifo(uint64_t *data); + int try_read_mc_request_fifo(uint64_t *data); + + public: + int tx_fifo_req(hb_mc_request_packet_t *packet); + int tx_fifo_rsp(hb_mc_response_packet_t *packet); + int rx_fifo_req(hb_mc_request_packet_t *packet); + int rx_fifo_rsp(hb_mc_response_packet_t *packet); + int mmio_read(uint64_t address, int32_t *data); + int mmio_write(uint64_t address, int32_t data, uint8_t mask); + int fifo_fence(); + int fifo_drain(); +}; + +#endif + diff --git a/libraries/platforms/hammerblade-vcs/bsg_manycore_regression_platform.h b/libraries/platforms/hammerblade-vcs/bsg_manycore_regression_platform.h new file mode 100644 index 000000000..1a4d9cb27 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/bsg_manycore_regression_platform.h @@ -0,0 +1,45 @@ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +// Defined by the linker script for riscv64-unknown-elf-dramfs-gcc + +// To make your program HammerBlade cross-platform compatible, +// define a function with the signature of "main", and then +// use this macro to mark it as the entry point of your program +// +// Example: +// +// int MyMain(int argc, char *argv[]) { +// /* your code here */ +// } +// declare_program_main("The name of your test", MyMain) +// +#define declare_program_main(test_name, name) \ + \ + int _argc = __init_argc; \ + char _argv_flat[100]; /* Up to 100 characters */ \ + char* _argv[10]; /* Up to ten arguments */ \ + int main() { \ + int i = 0; \ + int j = 0; \ + _argv[j++] = &_argv_flat[i]; \ + do { \ + if (__init_argv[i] == ' ') { \ + _argv_flat[i] = '\0'; \ + _argv[j++] = &_argv_flat[i+1]; \ + } else { \ + _argv_flat[i] = __init_argv[i]; \ + } \ + } while (__init_argv[i++] != '\0'); \ + bsg_pr_test_info("Regression Test: %s\n", test_name); \ + int rc = name(_argc, _argv); \ + bsg_pr_test_pass_fail(rc == HB_MC_SUCCESS); \ + return rc; \ + } + + +#ifdef __cplusplus +} +#endif diff --git a/libraries/platforms/hammerblade-vcs/compilation.mk b/libraries/platforms/hammerblade-vcs/compilation.mk new file mode 100644 index 000000000..068e2de9a --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/compilation.mk @@ -0,0 +1,72 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile fragment defines rules for compilation of the C/C++ +# files for running regression tests. + +ORANGE=\033[0;33m +RED=\033[0;31m +NC=\033[0m + +# This file REQUIRES several variables to be set. They are typically +# set by the Makefile that includes this makefile.. +# + +CC = $(BLACKPARROT_SDK_DIR)/install/bin/riscv64-unknown-elf-dramfs-gcc +CXX = $(BLACKPARROT_SDK_DIR)/install/bin/riscv64-unknown-elf-dramfs-g++ +AR = $(BLACKPARROT_SDK_DIR)/install/bin/riscv64-unknown-elf-dramfs-ar + +DEFINES += -DFPGA +INCLUDES += -I$(LIBRARIES_PATH) +INCLUDES += -I$(BSG_PLATFORM_PATH) +INCLUDES += -I$(BSG_PLATFORM_PATH)/include + +LDFLAGS += -lstdc++ -lc -L$(BSG_PLATFORM_PATH) -mcmodel=medany +CXXFLAGS += -O3 $(DEFINES) -fPIC -D_BSD_SOURCE -DGP0_ENABLE -DGP0_ADDR_BASE=0x40000000 -nostartfiles +CFLAGS += -O3 $(DEFINES) -fPIC -D_BSD_SOURCE -DGP0_ENABLE -DGP0_ADDR_BASE=0x40000000 -nostartfiles + +ARGV += "$(subst $(BSG_MANYCORE_KERNELS), $(notdir $(BSG_MANYCORE_KERNELS)),test_loader $(C_ARGS))" + +CDEFINES += -D__init_argc=$(words $(ARGV)) -D__init_argv=\"$(strip $(ARGV))\" +CXXDEFINES += -D__init_argc=$(words $(ARGV)) -D__init_argv=\"$(strip $(ARGV))\" + +# each regression target needs to build its .o from a .c and .h of the +# same name +%.o: %.c + $(CC) -c -o $@ $< $(INCLUDES) $(CFLAGS) $(CDEFINES) + +# ... or a .cpp and .hpp of the same name +%.o: %.cpp + $(CXX) -c -o $@ $< $(INCLUDES) $(CXXFLAGS) $(CXXDEFINES) + +.PRECIOUS: %.o + +.PHONY: platform.compilation.clean +platform.compilation.clean: + rm -rf *.o + +compilation.clean: platform.compilation.clean diff --git a/libraries/platforms/hammerblade-vcs/execution.mk b/libraries/platforms/hammerblade-vcs/execution.mk new file mode 100644 index 000000000..c21177cc6 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/execution.mk @@ -0,0 +1,58 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile fragment defines the rules that are used for executing +# applications on HammerBlade Platforms + +.PRECIOUS: exec.log saifgen.log +.PHONY: platform.execution.clean + +RISCV_DEFINES += -Dbsg_tiles_X=$(BSG_MACHINE_POD_TILES_X) +RISCV_DEFINES += -Dbsg_tiles_Y=$(BSG_MACHINE_POD_TILES_Y) +include $(BSG_F1_DIR)/examples/cuda/riscv.mk + +# TODO: This will always dump waves. To not dump waves, pass TRACE="" +# We should do this automatically on exec.log (not debug.log) +%.log: ZYNQPARROT_EXECUTION_DIR ?= $(ZYNQPARROT_DIR)/cosim/hammerblade-example/vcs +%.log: loader.o clr.riscv + $(MAKE) -C $(ZYNQPARROT_EXECUTION_DIR) clean + cp clr.riscv $(ZYNQPARROT_EXECUTION_DIR)/clr.riscv32 + cp loader.o $(ZYNQPARROT_EXECUTION_DIR)/loader.riscv64 + $(MAKE) -C $(ZYNQPARROT_EXECUTION_DIR) \ + NUM_MC_FINISH=0 \ + NUM_BP_FINISH=1 \ + BSG_REPLICANT_DIR=$(BSG_F1_DIR) \ + BSG_MANYCORE_DIR=$(BSG_MANYCORE_DIR) \ + BSG_MACHINE_PATH=$(BSG_MACHINE_PATH) \ + NBF_FILE=clr.loader.nbf \ + run + +platform.execution.clean: + rm -rf exec.log + +execution.clean: platform.execution.clean + diff --git a/libraries/platforms/hammerblade-vcs/hardware.mk b/libraries/platforms/hammerblade-vcs/hardware.mk new file mode 100644 index 000000000..95955d1c5 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/hardware.mk @@ -0,0 +1,46 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# hardware.mk: Platform-specific HDL listing. +# +# For simulation platforms, it also describes how to build the +# simulation "libraries" that are required by CAD tools. +# +# This file should be included from bsg_replicant/hardware/hardware.mk. It checks +# BSG_PLATFORM_PATH, BASEJUMP_STL_DIR, BSG_MANYCORE_DIR, etc. + +VSOURCES += $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v +ASCII_TO_ROM_PY = $(BASEJUMP_STL_DIR)/bsg_mem/bsg_ascii_to_rom.py +$(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v: $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.rom + env python2 $(ASCII_TO_ROM_PY) $< bsg_bladerunner_configuration > $@ + +.PRECIOUS: $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v + +hardware.clean: machine.hardware.clean + +machine.hardware.clean: + rm -f $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v diff --git a/libraries/platforms/hammerblade-vcs/include/argp-fmtstream.h b/libraries/platforms/hammerblade-vcs/include/argp-fmtstream.h new file mode 100644 index 000000000..128558021 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/argp-fmtstream.h @@ -0,0 +1,278 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Word-wrapping and line-truncating streams. + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This package emulates glibc `line_wrap_stream' semantics for systems that + don't have that. If the system does have it, it is just a wrapper for + that. This header file is only used internally while compiling argp, and + shouldn't be installed. */ + +#ifndef _ARGP_FMTSTREAM_H +#define _ARGP_FMTSTREAM_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#if (_LIBC - 0 && !defined (USE_IN_LIBIO)) \ + || (defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H)) +/* line_wrap_stream is available, so use that. */ +#define ARGP_FMTSTREAM_USE_LINEWRAP +#endif + +#ifdef ARGP_FMTSTREAM_USE_LINEWRAP +/* Just be a simple wrapper for line_wrap_stream; the semantics are + *slightly* different, as line_wrap_stream doesn't actually make a new + object, it just modifies the given stream (reversibly) to do + line-wrapping. Since we control who uses this code, it doesn't matter. */ + +#include + +typedef FILE *argp_fmtstream_t; + +#define argp_make_fmtstream line_wrap_stream +#define __argp_make_fmtstream line_wrap_stream +#define argp_fmtstream_free line_unwrap_stream +#define __argp_fmtstream_free line_unwrap_stream + +#define __argp_fmtstream_putc(fs,ch) putc(ch,fs) +#define argp_fmtstream_putc(fs,ch) putc(ch,fs) +#define __argp_fmtstream_puts(fs,str) fputs(str,fs) +#define argp_fmtstream_puts(fs,str) fputs(str,fs) +#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs) +#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs) +#define __argp_fmtstream_printf fprintf +#define argp_fmtstream_printf fprintf + +#define __argp_fmtstream_lmargin line_wrap_lmargin +#define argp_fmtstream_lmargin line_wrap_lmargin +#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin +#define argp_fmtstream_set_lmargin line_wrap_set_lmargin +#define __argp_fmtstream_rmargin line_wrap_rmargin +#define argp_fmtstream_rmargin line_wrap_rmargin +#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin +#define argp_fmtstream_set_rmargin line_wrap_set_rmargin +#define __argp_fmtstream_wmargin line_wrap_wmargin +#define argp_fmtstream_wmargin line_wrap_wmargin +#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin +#define argp_fmtstream_set_wmargin line_wrap_set_wmargin +#define __argp_fmtstream_point line_wrap_point +#define argp_fmtstream_point line_wrap_point + +#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */ +/* Guess we have to define our own version. */ + +#ifndef __const +#define __const const +#endif + +struct argp_fmtstream +{ + FILE *stream; /* The stream we're outputting to. */ + + size_t lmargin, rmargin; /* Left and right margins. */ + ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */ + + /* Point in buffer to which we've processed for wrapping, but not output. */ + size_t point_offs; + /* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin. */ + ssize_t point_col; + + char *buf; /* Output buffer. */ + char *p; /* Current end of text in BUF. */ + char *end; /* Absolute end of BUF. */ +}; + +typedef struct argp_fmtstream *argp_fmtstream_t; + +/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by + replacing the whitespace before them with a newline and WMARGIN spaces. + Otherwise, chars beyond RMARGIN are simply dropped until a newline. + Returns NULL if there was an error. */ +extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream, + size_t __lmargin, + size_t __rmargin, + ssize_t __wmargin); +extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream, + size_t __lmargin, + size_t __rmargin, + ssize_t __wmargin); + +/* Flush __FS to its stream, and free it (but don't close the stream). */ +extern void __argp_fmtstream_free (argp_fmtstream_t __fs); +extern void argp_fmtstream_free (argp_fmtstream_t __fs); + +extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs, + __const char *__fmt, ...) + __attribute__ ((__format__ (printf, 2, 3))); +extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs, + __const char *__fmt, ...) + __attribute__ ((__format__ (printf, 2, 3))); + +/* Access macros for various bits of state. */ +#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin) +#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin) +#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin) +#define __argp_fmtstream_lmargin argp_fmtstream_lmargin +#define __argp_fmtstream_rmargin argp_fmtstream_rmargin +#define __argp_fmtstream_wmargin argp_fmtstream_wmargin + +/* Internal routines. */ +extern void _argp_fmtstream_update (argp_fmtstream_t __fs); +extern void __argp_fmtstream_update (argp_fmtstream_t __fs); +extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); +extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount); + +/* Inline versions of above routines. */ + +#if !_LIBC +#define __argp_fmtstream_putc argp_fmtstream_putc +#define __argp_fmtstream_puts argp_fmtstream_puts +#define __argp_fmtstream_write argp_fmtstream_write +#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin +#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin +#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin +#define __argp_fmtstream_point argp_fmtstream_point +#define __argp_fmtstream_update _argp_fmtstream_update +#define __argp_fmtstream_ensure _argp_fmtstream_ensure +#endif + +static inline size_t __argp_fmtstream_write (argp_fmtstream_t __fs, __const char *__str, size_t __len) +{ + if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len)) + { + memcpy (__fs->p, __str, __len); + __fs->p += __len; + return __len; + } + else + return 0; +} + +static inline int __argp_fmtstream_puts (argp_fmtstream_t __fs, __const char *__str) +{ + size_t __len = strlen (__str); + if (__len) + { + size_t __wrote = __argp_fmtstream_write (__fs, __str, __len); + return __wrote == __len ? 0 : -1; + } + else + return 0; +} + +static inline int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch) +{ + if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1)) + return *__fs->p++ = __ch; + else + return EOF; +} + +/* Set __FS's left margin to LMARGIN and return the old value. */ +static inline size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->lmargin; + __fs->lmargin = __lmargin; + return __old; +} + +/* Set __FS's right margin to __RMARGIN and return the old value. */ +static inline size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->rmargin; + __fs->rmargin = __rmargin; + return __old; +} + +/* Set __FS's wrap margin to __WMARGIN and return the old value. */ +static inline size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin) +{ + size_t __old; + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + __old = __fs->wmargin; + __fs->wmargin = __wmargin; + return __old; +} + +/* Return the column number of the current output point in __FS. */ +static inline size_t __argp_fmtstream_point (argp_fmtstream_t __fs) +{ + if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) + __argp_fmtstream_update (__fs); + return __fs->point_col >= 0 ? __fs->point_col : 0; +} + +#if !_LIBC +#undef __argp_fmtstream_putc +#undef __argp_fmtstream_puts +#undef __argp_fmtstream_write +#undef __argp_fmtstream_set_lmargin +#undef __argp_fmtstream_set_rmargin +#undef __argp_fmtstream_set_wmargin +#undef __argp_fmtstream_point +#undef __argp_fmtstream_update +#undef __argp_fmtstream_ensure +#endif + +#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ + +#endif /* argp-fmtstream.h */ diff --git a/libraries/platforms/hammerblade-vcs/include/argp-namefrob.h b/libraries/platforms/hammerblade-vcs/include/argp-namefrob.h new file mode 100644 index 000000000..cf034e6e8 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/argp-namefrob.h @@ -0,0 +1,121 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Name frobnication for compiling argp outside of glibc + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#if !_LIBC +/* This code is written for inclusion in gnu-libc, and uses names in the + namespace reserved for libc. If we're not compiling in libc, define those + names to be the normal ones instead. */ + +/* argp-parse functions */ +#undef __argp_parse +#define __argp_parse argp_parse +#undef __option_is_end +#define __option_is_end _option_is_end +#undef __option_is_short +#define __option_is_short _option_is_short +#undef __argp_input +#define __argp_input _argp_input + +/* argp-help functions */ +#undef __argp_help +#define __argp_help argp_help +#undef __argp_error +#define __argp_error argp_error +#undef __argp_failure +#define __argp_failure argp_failure +#undef __argp_state_help +#define __argp_state_help argp_state_help +#undef __argp_usage +#define __argp_usage argp_usage + +/* argp-fmtstream functions */ +#undef __argp_make_fmtstream +#define __argp_make_fmtstream argp_make_fmtstream +#undef __argp_fmtstream_free +#define __argp_fmtstream_free argp_fmtstream_free +#undef __argp_fmtstream_putc +#define __argp_fmtstream_putc argp_fmtstream_putc +#undef __argp_fmtstream_puts +#define __argp_fmtstream_puts argp_fmtstream_puts +#undef __argp_fmtstream_write +#define __argp_fmtstream_write argp_fmtstream_write +#undef __argp_fmtstream_printf +#define __argp_fmtstream_printf argp_fmtstream_printf +#undef __argp_fmtstream_set_lmargin +#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin +#undef __argp_fmtstream_set_rmargin +#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin +#undef __argp_fmtstream_set_wmargin +#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin +#undef __argp_fmtstream_point +#define __argp_fmtstream_point argp_fmtstream_point +#undef __argp_fmtstream_update +#define __argp_fmtstream_update _argp_fmtstream_update +#undef __argp_fmtstream_ensure +#define __argp_fmtstream_ensure _argp_fmtstream_ensure +#undef __argp_fmtstream_lmargin +#define __argp_fmtstream_lmargin argp_fmtstream_lmargin +#undef __argp_fmtstream_rmargin +#define __argp_fmtstream_rmargin argp_fmtstream_rmargin +#undef __argp_fmtstream_wmargin +#define __argp_fmtstream_wmargin argp_fmtstream_wmargin + +/* normal libc functions we call */ +#undef __sleep +#define __sleep sleep +#undef __strcasecmp +#define __strcasecmp strcasecmp +#undef __vsnprintf +#define __vsnprintf vsnprintf + +#endif /* !_LIBC */ + +#ifndef __set_errno +#define __set_errno(e) (errno = (e)) +#endif diff --git a/libraries/platforms/hammerblade-vcs/include/argp.h b/libraries/platforms/hammerblade-vcs/include/argp.h new file mode 100644 index 000000000..43dde05fa --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/argp.h @@ -0,0 +1,597 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Hierarchial argument parsing, layered over getopt. + Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _ARGP_H +#define _ARGP_H + +#include +#include +#include + +#define __need_error_t +#include + +char *program_invocation_name; +char *program_invocation_short_name; + +#ifndef __const +# define __const const +#endif + +#ifndef __error_t_defined +typedef int error_t; +# define __error_t_defined +#endif + +#undef __THROW +#define __THROW + +#ifndef __NTH +# define __NTH(fct) fct __THROW +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* A description of a particular option. A pointer to an array of + these is passed in the OPTIONS field of an argp structure. Each option + entry can correspond to one long option and/or one short option; more + names for the same option can be added by following an entry in an option + array with options having the OPTION_ALIAS flag set. */ +struct argp_option +{ + /* The long option name. For more than one name for the same option, you + can use following options with the OPTION_ALIAS flag set. */ + __const char *name; + + /* What key is returned for this option. If > 0 and printable, then it's + also accepted as a short option. */ + int key; + + /* If non-NULL, this is the name of the argument associated with this + option, which is required unless the OPTION_ARG_OPTIONAL flag is set. */ + __const char *arg; + + /* OPTION_ flags. */ + int flags; + + /* The doc string for this option. If both NAME and KEY are 0, This string + will be printed outdented from the normal option column, making it + useful as a group header (it will be the first thing printed in its + group); in this usage, it's conventional to end the string with a `:'. */ + __const char *doc; + + /* The group this option is in. In a long help message, options are sorted + alphabetically within each group, and the groups presented in the order + 0, 1, 2, ..., n, -m, ..., -2, -1. Every entry in an options array with + if this field 0 will inherit the group number of the previous entry, or + zero if it's the first one, unless its a group header (NAME and KEY both + 0), in which case, the previous entry + 1 is the default. Automagic + options such as --help are put into group -1. */ + int group; +}; + +/* The argument associated with this option is optional. */ +#define OPTION_ARG_OPTIONAL 0x1 + +/* This option isn't displayed in any help messages. */ +#define OPTION_HIDDEN 0x2 + +/* This option is an alias for the closest previous non-alias option. This + means that it will be displayed in the same help entry, and will inherit + fields other than NAME and KEY from the aliased option. */ +#define OPTION_ALIAS 0x4 + +/* This option isn't actually an option (and so should be ignored by the + actual option parser), but rather an arbitrary piece of documentation that + should be displayed in much the same manner as the options. If this flag + is set, then the option NAME field is displayed unmodified (e.g., no `--' + prefix is added) at the left-margin (where a *short* option would normally + be displayed), and the documentation string in the normal place. For + purposes of sorting, any leading whitespace and puncuation is ignored, + except that if the first non-whitespace character is not `-', this entry + is displayed after all options (and OPTION_DOC entries with a leading `-') + in the same group. */ +#define OPTION_DOC 0x8 + +/* This option shouldn't be included in `long' usage messages (but is still + included in help messages). This is mainly intended for options that are + completely documented in an argp's ARGS_DOC field, in which case including + the option in the generic usage list would be redundant. For instance, + if ARGS_DOC is "FOO BAR\n-x BLAH", and the `-x' option's purpose is to + distinguish these two cases, -x should probably be marked + OPTION_NO_USAGE. */ +#define OPTION_NO_USAGE 0x10 + +struct argp; /* fwd declare this type */ +struct argp_state; /* " */ +struct argp_child; /* " */ + +/* The type of a pointer to an argp parsing function. */ +typedef error_t (*argp_parser_t) (int key, char *arg, + struct argp_state *state); + +/* What to return for unrecognized keys. For special ARGP_KEY_ keys, such + returns will simply be ignored. For user keys, this error will be turned + into EINVAL (if the call to argp_parse is such that errors are propagated + back to the user instead of exiting); returning EINVAL itself would result + in an immediate stop to parsing in *all* cases. */ +#define ARGP_ERR_UNKNOWN E2BIG /* Hurd should never need E2BIG. XXX */ + +/* Special values for the KEY argument to an argument parsing function. + ARGP_ERR_UNKNOWN should be returned if they aren't understood. + + The sequence of keys to a parsing function is either (where each + uppercased word should be prefixed by `ARGP_KEY_' and opt is a user key): + + INIT opt... NO_ARGS END SUCCESS -- No non-option arguments at all + or INIT (opt | ARG)... END SUCCESS -- All non-option args parsed + or INIT (opt | ARG)... SUCCESS -- Some non-option arg unrecognized + + The third case is where every parser returned ARGP_KEY_UNKNOWN for an + argument, in which case parsing stops at that argument (returning the + unparsed arguments to the caller of argp_parse if requested, or stopping + with an error message if not). + + If an error occurs (either detected by argp, or because the parsing + function returned an error value), then the parser is called with + ARGP_KEY_ERROR, and no further calls are made. */ + +/* This is not an option at all, but rather a command line argument. If a + parser receiving this key returns success, the fact is recorded, and the + ARGP_KEY_NO_ARGS case won't be used. HOWEVER, if while processing the + argument, a parser function decrements the NEXT field of the state it's + passed, the option won't be considered processed; this is to allow you to + actually modify the argument (perhaps into an option), and have it + processed again. */ +#define ARGP_KEY_ARG 0 +/* There are remaining arguments not parsed by any parser, which may be found + starting at (STATE->argv + STATE->next). If success is returned, but + STATE->next left untouched, it's assumed that all arguments were consume, + otherwise, the parser should adjust STATE->next to reflect any arguments + consumed. */ +#define ARGP_KEY_ARGS 0x1000006 +/* There are no more command line arguments at all. */ +#define ARGP_KEY_END 0x1000001 +/* Because it's common to want to do some special processing if there aren't + any non-option args, user parsers are called with this key if they didn't + successfully process any non-option arguments. Called just before + ARGP_KEY_END (where more general validity checks on previously parsed + arguments can take place). */ +#define ARGP_KEY_NO_ARGS 0x1000002 +/* Passed in before any parsing is done. Afterwards, the values of each + element of the CHILD_INPUT field, if any, in the state structure is + copied to each child's state to be the initial value of the INPUT field. */ +#define ARGP_KEY_INIT 0x1000003 +/* Use after all other keys, including SUCCESS & END. */ +#define ARGP_KEY_FINI 0x1000007 +/* Passed in when parsing has successfully been completed (even if there are + still arguments remaining). */ +#define ARGP_KEY_SUCCESS 0x1000004 +/* Passed in if an error occurs. */ +#define ARGP_KEY_ERROR 0x1000005 + +/* An argp structure contains a set of options declarations, a function to + deal with parsing one, documentation string, a possible vector of child + argp's, and perhaps a function to filter help output. When actually + parsing options, getopt is called with the union of all the argp + structures chained together through their CHILD pointers, with conflicts + being resolved in favor of the first occurrence in the chain. */ +struct argp +{ + /* An array of argp_option structures, terminated by an entry with both + NAME and KEY having a value of 0. */ + __const struct argp_option *options; + + /* What to do with an option from this structure. KEY is the key + associated with the option, and ARG is any associated argument (NULL if + none was supplied). If KEY isn't understood, ARGP_ERR_UNKNOWN should be + returned. If a non-zero, non-ARGP_ERR_UNKNOWN value is returned, then + parsing is stopped immediately, and that value is returned from + argp_parse(). For special (non-user-supplied) values of KEY, see the + ARGP_KEY_ definitions below. */ + argp_parser_t parser; + + /* A string describing what other arguments are wanted by this program. It + is only used by argp_usage to print the `Usage:' message. If it + contains newlines, the strings separated by them are considered + alternative usage patterns, and printed on separate lines (lines after + the first are prefix by ` or: ' instead of `Usage:'). */ + __const char *args_doc; + + /* If non-NULL, a string containing extra text to be printed before and + after the options in a long help message (separated by a vertical tab + `\v' character). */ + __const char *doc; + + /* A vector of argp_children structures, terminated by a member with a 0 + argp field, pointing to child argps should be parsed with this one. Any + conflicts are resolved in favor of this argp, or early argps in the + CHILDREN list. This field is useful if you use libraries that supply + their own argp structure, which you want to use in conjunction with your + own. */ + __const struct argp_child *children; + + /* If non-zero, this should be a function to filter the output of help + messages. KEY is either a key from an option, in which case TEXT is + that option's help text, or a special key from the ARGP_KEY_HELP_ + defines, below, describing which other help text TEXT is. The function + should return either TEXT, if it should be used as-is, a replacement + string, which should be malloced, and will be freed by argp, or NULL, + meaning `print nothing'. The value for TEXT is *after* any translation + has been done, so if any of the replacement text also needs translation, + that should be done by the filter function. INPUT is either the input + supplied to argp_parse, or NULL, if argp_help was called directly. */ + char *(*help_filter) (int __key, __const char *__text, void *__input); + + /* If non-zero the strings used in the argp library are translated using + the domain described by this string. Otherwise the currently installed + default domain is used. */ + const char *argp_domain; +}; + +/* Possible KEY arguments to a help filter function. */ +#define ARGP_KEY_HELP_PRE_DOC 0x2000001 /* Help text preceeding options. */ +#define ARGP_KEY_HELP_POST_DOC 0x2000002 /* Help text following options. */ +#define ARGP_KEY_HELP_HEADER 0x2000003 /* Option header string. */ +#define ARGP_KEY_HELP_EXTRA 0x2000004 /* After all other documentation; + TEXT is NULL for this key. */ +/* Explanatory note emitted when duplicate option arguments have been + suppressed. */ +#define ARGP_KEY_HELP_DUP_ARGS_NOTE 0x2000005 +#define ARGP_KEY_HELP_ARGS_DOC 0x2000006 /* Argument doc string. */ + +/* When an argp has a non-zero CHILDREN field, it should point to a vector of + argp_child structures, each of which describes a subsidiary argp. */ +struct argp_child +{ + /* The child parser. */ + __const struct argp *argp; + + /* Flags for this child. */ + int flags; + + /* If non-zero, an optional header to be printed in help output before the + child options. As a side-effect, a non-zero value forces the child + options to be grouped together; to achieve this effect without actually + printing a header string, use a value of "". */ + __const char *header; + + /* Where to group the child options relative to the other (`consolidated') + options in the parent argp; the values are the same as the GROUP field + in argp_option structs, but all child-groupings follow parent options at + a particular group level. If both this field and HEADER are zero, then + they aren't grouped at all, but rather merged with the parent options + (merging the child's grouping levels with the parents). */ + int group; +}; + +/* Parsing state. This is provided to parsing functions called by argp, + which may examine and, as noted, modify fields. */ +struct argp_state +{ + /* The top level ARGP being parsed. */ + __const struct argp *root_argp; + + /* The argument vector being parsed. May be modified. */ + int argc; + char **argv; + + /* The index in ARGV of the next arg that to be parsed. May be modified. */ + int next; + + /* The flags supplied to argp_parse. May be modified. */ + unsigned flags; + + /* While calling a parsing function with a key of ARGP_KEY_ARG, this is the + number of the current arg, starting at zero, and incremented after each + such call returns. At all other times, this is the number of such + arguments that have been processed. */ + unsigned arg_num; + + /* If non-zero, the index in ARGV of the first argument following a special + `--' argument (which prevents anything following being interpreted as an + option). Only set once argument parsing has proceeded past this point. */ + int quoted; + + /* An arbitrary pointer passed in from the user. */ + void *input; + /* Values to pass to child parsers. This vector will be the same length as + the number of children for the current parser. */ + void **child_inputs; + + /* For the parser's use. Initialized to 0. */ + void *hook; + + /* The name used when printing messages. This is initialized to ARGV[0], + or PROGRAM_INVOCATION_NAME if that is unavailable. */ + char *name; + + /* Streams used when argp prints something. */ + FILE *err_stream; /* For errors; initialized to stderr. */ + FILE *out_stream; /* For information; initialized to stdout. */ + + void *pstate; /* Private, for use by argp. */ +}; + +/* Flags for argp_parse (note that the defaults are those that are + convenient for program command line parsing): */ + +/* Don't ignore the first element of ARGV. Normally (and always unless + ARGP_NO_ERRS is set) the first element of the argument vector is + skipped for option parsing purposes, as it corresponds to the program name + in a command line. */ +#define ARGP_PARSE_ARGV0 0x01 + +/* Don't print error messages for unknown options to stderr; unless this flag + is set, ARGP_PARSE_ARGV0 is ignored, as ARGV[0] is used as the program + name in the error messages. This flag implies ARGP_NO_EXIT (on the + assumption that silent exiting upon errors is bad behaviour). */ +#define ARGP_NO_ERRS 0x02 + +/* Don't parse any non-option args. Normally non-option args are parsed by + calling the parse functions with a key of ARGP_KEY_ARG, and the actual arg + as the value. Since it's impossible to know which parse function wants to + handle it, each one is called in turn, until one returns 0 or an error + other than ARGP_ERR_UNKNOWN; if an argument is handled by no one, the + argp_parse returns prematurely (but with a return value of 0). If all + args have been parsed without error, all parsing functions are called one + last time with a key of ARGP_KEY_END. This flag needn't normally be set, + as the normal behavior is to stop parsing as soon as some argument can't + be handled. */ +#define ARGP_NO_ARGS 0x04 + +/* Parse options and arguments in the same order they occur on the command + line -- normally they're rearranged so that all options come first. */ +#define ARGP_IN_ORDER 0x08 + +/* Don't provide the standard long option --help, which causes usage and + option help information to be output to stdout, and exit (0) called. */ +#define ARGP_NO_HELP 0x10 + +/* Don't exit on errors (they may still result in error messages). */ +#define ARGP_NO_EXIT 0x20 + +/* Use the gnu getopt `long-only' rules for parsing arguments. */ +#define ARGP_LONG_ONLY 0x40 + +/* Turns off any message-printing/exiting options. */ +#define ARGP_SILENT (ARGP_NO_EXIT | ARGP_NO_ERRS | ARGP_NO_HELP) + +/* Parse the options strings in ARGC & ARGV according to the options in ARGP. + FLAGS is one of the ARGP_ flags above. If ARG_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, ARGP_ERR_UNKNOWN is returned; if some parser + routine returned a non-zero value, it is returned; otherwise 0 is + returned. This function may also call exit unless the ARGP_NO_HELP flag + is set. INPUT is a pointer to a value to be passed in to the parser. */ +extern error_t argp_parse (__const struct argp *__restrict __argp, + int __argc, char **__restrict __argv, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input) __THROW; +extern error_t __argp_parse (__const struct argp *__restrict __argp, + int __argc, char **__restrict __argv, + unsigned __flags, int *__restrict __arg_index, + void *__restrict __input) __THROW; + +/* Global variables. */ + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + will print this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +extern __const char *argp_program_version; + +/* If defined or set by the user program to a non-zero value, then a default + option --version is added (unless the ARGP_NO_HELP flag is used), which + calls this function with a stream to print the version to and a pointer to + the current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +extern void (*argp_program_version_hook) (FILE *__restrict __stream, + struct argp_state *__restrict + __state); + +/* If defined or set by the user program, it should point to string that is + the bug-reporting address for the program. It will be printed by + argp_help if the ARGP_HELP_BUG_ADDR flag is set (as it is by various + standard help messages), embedded in a sentence that says something like + `Report bugs to ADDR.'. */ +extern __const char *argp_program_bug_address; + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + . */ +extern error_t argp_err_exit_status; + +/* Flags for argp_help. */ +#define ARGP_HELP_USAGE 0x01 /* a Usage: message. */ +#define ARGP_HELP_SHORT_USAGE 0x02 /* " but don't actually print options. */ +#define ARGP_HELP_SEE 0x04 /* a `Try ... for more help' message. */ +#define ARGP_HELP_LONG 0x08 /* a long help message. */ +#define ARGP_HELP_PRE_DOC 0x10 /* doc string preceding long help. */ +#define ARGP_HELP_POST_DOC 0x20 /* doc string following long help. */ +#define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC) +#define ARGP_HELP_BUG_ADDR 0x40 /* bug report address */ +#define ARGP_HELP_LONG_ONLY 0x80 /* modify output appropriately to + reflect ARGP_LONG_ONLY mode. */ + +/* These ARGP_HELP flags are only understood by argp_state_help. */ +#define ARGP_HELP_EXIT_ERR 0x100 /* Call exit(1) instead of returning. */ +#define ARGP_HELP_EXIT_OK 0x200 /* Call exit(0) instead of returning. */ + +/* The standard thing to do after a program command line parsing error, if an + error message has already been printed. */ +#define ARGP_HELP_STD_ERR \ + (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do after a program command line parsing error, if no + more specific error message has been printed. */ +#define ARGP_HELP_STD_USAGE \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR) +/* The standard thing to do in response to a --help option. */ +#define ARGP_HELP_STD_HELP \ + (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK \ + | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR) + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. */ +extern void argp_help (__const struct argp *__restrict __argp, + FILE *__restrict __stream, + unsigned __flags, char *__restrict __name) __THROW; +extern void __argp_help (__const struct argp *__restrict __argp, + FILE *__restrict __stream, unsigned __flags, + char *__name) __THROW; + +/* The following routines are intended to be called from within an argp + parsing routine (thus taking an argp_state structure as the first + argument). They may or may not print an error message and exit, depending + on the flags in STATE -- in any case, the caller should be prepared for + them *not* to exit, and should return an appropiate error after calling + them. [argp_usage & argp_error should probably be called argp_state_..., + but they're used often enough that they should be short] */ + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +extern void argp_state_help (__const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags) __THROW; +extern void __argp_state_help (__const struct argp_state *__restrict __state, + FILE *__restrict __stream, + unsigned int __flags) __THROW; + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +extern void argp_error (__const struct argp_state *__restrict __state, + __const char *__restrict __fmt, ...) __THROW + __attribute__ ((__format__ (__printf__, 2, 3))); +extern void __argp_error (__const struct argp_state *__restrict __state, + __const char *__restrict __fmt, ...) __THROW + __attribute__ ((__format__ (__printf__, 2, 3))); + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +extern void argp_failure (__const struct argp_state *__restrict __state, + int __status, int __errnum, + __const char *__restrict __fmt, ...) __THROW + __attribute__ ((__format__ (__printf__, 4, 5))); +extern void __argp_failure (__const struct argp_state *__restrict __state, + int __status, int __errnum, + __const char *__restrict __fmt, ...) __THROW + __attribute__ ((__format__ (__printf__, 4, 5))); + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +extern void *_argp_input (__const struct argp *__restrict __argp, + __const struct argp_state *__restrict __state) + __THROW; +extern void *__argp_input (__const struct argp *__restrict __argp, + __const struct argp_state *__restrict __state) + __THROW; + +// Sripathi: +// Always define functions in a header file with the static modifier. +// Defining functions with "extern inline" in a header file is just wrong. +// Switch to using "static inline" to make the function visible wherever +// this header file is included + +# if !_LIBC +# define __argp_usage argp_usage +# define __argp_state_help argp_state_help +# define __option_is_short _option_is_short +# define __option_is_end _option_is_end +# endif + +/* Possibly output the standard usage message for ARGP to stderr and exit. */ +static inline void +__argp_usage (__const struct argp_state *__state) __THROW +{ + __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE); +} + +/* Returns true if the option OPT is a valid short option. */ +static inline int +__option_is_short (__const struct argp_option *__opt) __THROW +{ + if (__opt->flags & OPTION_DOC) + return 0; + else + { + int __key = __opt->key; + return __key > 0 && isprint (__key); + } +} + +/* Returns true if the option OPT is in fact the last (unused) entry in an + options array. */ +static inline int +__option_is_end (__const struct argp_option *__opt) __THROW +{ + return !__opt->key && !__opt->name && !__opt->doc && !__opt->group; +} + +# if !_LIBC +# undef __argp_usage +# undef __argp_state_help +# undef __option_is_short +# undef __option_is_end +# endif + +#ifdef __cplusplus +} +#endif + +#endif /* argp.h */ diff --git a/libraries/platforms/hammerblade-vcs/include/bsg_newlib_intf.h b/libraries/platforms/hammerblade-vcs/include/bsg_newlib_intf.h new file mode 100644 index 000000000..84fa0ce95 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/bsg_newlib_intf.h @@ -0,0 +1,8 @@ +#include +#include + +void dramfs_init(void); +void dramfs_exit(int exit_status); +void dramfs_sendchar(char ch); +int dramfs_getchar(void); + diff --git a/libraries/platforms/hammerblade-vcs/include/endian.h b/libraries/platforms/hammerblade-vcs/include/endian.h new file mode 100644 index 000000000..db84ae0a0 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/endian.h @@ -0,0 +1,51 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Note: Users should only use this file for compiling with NEWLIB + +// In GLIBC, this header file is present in the default include path however +// in NEWLIB, the same header file is present in /machine/ +// therefore, this dummy file is used to actually call the correct header file in +// NEWLIB whilst still maintaining the same interface as GLIBC. This is done to prevent +// changes to the CUDA-lite library code. + +#ifndef _ENDIAN_H +#define _ENDIAN_H + +#include + +#if defined(_DEFAULT_SOURCE) && (!defined(__ASSEMBLER__)) +// BlackParrot is Little Endian +#define le16toh(_x) ((__uint16_t)(_x)) +#define htole16(_x) ((__uint16_t)(_x)) +#define le32toh(_x) ((__uint32_t)(_x)) +#define htole32(_x) ((__uint32_t)(_x)) +#define le64toh(_x) ((__uint64_t)(_x)) +#define htole64(_x) ((__uint64_t)(_x)) +#endif + +#endif/* _ENDIAN_H__ */ diff --git a/libraries/platforms/hammerblade-vcs/include/features.h b/libraries/platforms/hammerblade-vcs/include/features.h new file mode 100644 index 000000000..acada50ca --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/features.h @@ -0,0 +1,41 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Note: Users should only use this file for compiling with NEWLIB + +// In GLIBC, this header file is present in the default include path however +// in NEWLIB, the same header file is present in /sys/ +// therefore, this dummy file is used to actually call the correct header file in +// NEWLIB whilst still maintaining the same interface as GLIBC. This is done to prevent +// changes to the CUDA-lite library code. + +#ifndef _FEATURES_H +#define _FEATURES_H + +#include + +#endif /* _FEATURES_H */ diff --git a/libraries/platforms/hammerblade-vcs/include/sys/ioctl.h b/libraries/platforms/hammerblade-vcs/include/sys/ioctl.h new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/platforms/hammerblade-vcs/include/sysexits.h b/libraries/platforms/hammerblade-vcs/include/sysexits.h new file mode 100644 index 000000000..8ac6e6ad9 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/include/sysexits.h @@ -0,0 +1,143 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// A copy of the system exit error codes file from GCC + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)sysexits.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _SYSEXITS_H +#define _SYSEXITS_H 1 + +/* + * SYSEXITS.H -- Exit status codes for system programs. + * + * This include file attempts to categorize possible error + * exit statuses for system programs, notably delivermail + * and the Berkeley network. + * + * Error numbers begin at EX__BASE to reduce the possibility of + * clashing with other exit statuses that random programs may + * already return. The meaning of the codes is approximately + * as follows: + * + * EX_USAGE -- The command was used incorrectly, e.g., with + * the wrong number of arguments, a bad flag, a bad + * syntax in a parameter, or whatever. + * EX_DATAERR -- The input data was incorrect in some way. + * This should only be used for user's data & not + * system files. + * EX_NOINPUT -- An input file (not a system file) did not + * exist or was not readable. This could also include + * errors like "No message" to a mailer (if it cared + * to catch it). + * EX_NOUSER -- The user specified did not exist. This might + * be used for mail addresses or remote logins. + * EX_NOHOST -- The host specified did not exist. This is used + * in mail addresses or network requests. + * EX_UNAVAILABLE -- A service is unavailable. This can occur + * if a support program or file does not exist. This + * can also be used as a catchall message when something + * you wanted to do doesn't work, but you don't know + * why. + * EX_SOFTWARE -- An internal software error has been detected. + * This should be limited to non-operating system related + * errors as possible. + * EX_OSERR -- An operating system error has been detected. + * This is intended to be used for such things as "cannot + * fork", "cannot create pipe", or the like. It includes + * things like getuid returning a user that does not + * exist in the passwd file. + * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp, + * etc.) does not exist, cannot be opened, or has some + * sort of error (e.g., syntax error). + * EX_CANTCREAT -- A (user specified) output file cannot be + * created. + * EX_IOERR -- An error occurred while doing I/O on some file. + * EX_TEMPFAIL -- temporary failure, indicating something that + * is not really an error. In sendmail, this means + * that a mailer (e.g.) could not create a connection, + * and the request should be reattempted later. + * EX_PROTOCOL -- the remote system returned something that + * was "not possible" during a protocol exchange. + * EX_NOPERM -- You did not have sufficient permission to + * perform the operation. This is not intended for + * file system problems, which should use NOINPUT or + * CANTCREAT, but rather for higher level permissions. + */ + +#define EX_OK 0 /* successful termination */ + +#define EX__BASE 64 /* base value for error messages */ + +#define EX_USAGE 64 /* command line usage error */ +#define EX_DATAERR 65 /* data format error */ +#define EX_NOINPUT 66 /* cannot open input */ +#define EX_NOUSER 67 /* addressee unknown */ +#define EX_NOHOST 68 /* host name unknown */ +#define EX_UNAVAILABLE 69 /* service unavailable */ +#define EX_SOFTWARE 70 /* internal software error */ +#define EX_OSERR 71 /* system error (e.g., can't fork) */ +#define EX_OSFILE 72 /* critical OS file missing */ +#define EX_CANTCREAT 73 /* can't create (user) output file */ +#define EX_IOERR 74 /* input/output error */ +#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */ +#define EX_PROTOCOL 76 /* remote error in protocol */ +#define EX_NOPERM 77 /* permission denied */ +#define EX_CONFIG 78 /* configuration error */ + +#define EX__MAX 78 /* maximum listed value */ + +#endif /* sysexits.h */ diff --git a/libraries/platforms/hammerblade-vcs/library.mk b/libraries/platforms/hammerblade-vcs/library.mk new file mode 100644 index 000000000..7643406d6 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/library.mk @@ -0,0 +1,82 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +PLATFORM_CXXSOURCES += $(LIBRARIES_PATH)/features/profiler/noimpl/bsg_manycore_profiler.cpp +PLATFORM_CXXSOURCES += $(LIBRARIES_PATH)/features/tracer/noimpl/bsg_manycore_tracer.cpp +PLATFORM_CXXSOURCES += $(LIBRARIES_PATH)/features/dma/blackparrot/bsg_manycore_dma.cpp +PLATFORM_CXXSOURCES += $(BSG_PLATFORM_PATH)/bsg_manycore_platform.cpp + +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-ba.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-eexst.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-fmtstream.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-fs-xinl.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-help.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-parse.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-pv.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-pvh.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/argp/argp-xinl.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/flockfile.c +LIB_CSOURCES += $(BSG_PLATFORM_PATH)/src/funlockfile.c + +include $(LIBRARIES_PATH)/features/dma/blackparrot/feature.mk + +PLATFORM_OBJECTS += $(patsubst %cpp,%o,$(PLATFORM_CXXSOURCES)) +PLATFORM_OBJECTS += $(patsubst %c,%o,$(PLATFORM_CSOURCES)) + +PLATFORM_REGRESSION_OBJECTS += $(patsubst %cpp,%o,$(PLATFORM_REGRESSION_CXXSOURCES)) +PLATFORM_REGRESSION_OBJECTS += $(patsubst %c,%o,$(PLATFORM_REGRESSION_CSOURCES)) + +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES := -I$(LIBRARIES_PATH) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(BSG_PLATFORM_PATH) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(BSG_PLATFORM_PATH)/include +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/dma +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/profiler +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/tracer +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(ZYNQPARROT_DIR)/cosim/include/common +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(ZYNQPARROT_DIR)/cosim/include/fpga +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): $(BSG_MACHINE_PATH)/bsg_manycore_machine.h +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(BSG_MACHINE_PATH) + +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(CL_DIR)/../aws-fpga/sdk/userspace/include +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CFLAGS := -O3 -std=c11 -fPIC -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CXXFLAGS := -O3 -std=c++11 -fPIC -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): LDFLAGS = -fPIC +$(PLATFORM_REGRESSION_OBJECTS): LDFLAGS = -ldl + +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.a: $(PLATFORM_OBJECTS) +$(BSG_PLATFORM_PATH)/libbsg_manycore_regression.a: $(PLATFORM_REGRESSION_OBJECTS) + +.PHONY: platform.clean install uninstall +platform.clean: + rm -f $(PLATFORM_OBJECTS) + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1 + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so* + rm -f $(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.so* + +libraries.clean: platform.clean + diff --git a/libraries/platforms/hammerblade-vcs/link.mk b/libraries/platforms/hammerblade-vcs/link.mk new file mode 100644 index 000000000..859d18296 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/link.mk @@ -0,0 +1,80 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile Fragment defines rules for linking object files for native +# regression tests + +# hardware.mk is the file list for the simulation RTL. It includes the +# platform specific hardware.mk file. +include $(HARDWARE_PATH)/hardware.mk + +# libraries.mk defines how to build libbsg_manycore_runtime.so, which is +# pre-linked against all other simulation binaries. +include $(LIBRARIES_PATH)/libraries.mk + +ORANGE=\033[0;33m +RED=\033[0;31m +NC=\033[0m + +# We transform C_ARGS to CDEFINES to pass directly +CDEFINES ?= + +LDFLAGS += -mcmodel=medany +LDFLAGS += -static +LDFLAGS += -fPIC +LDFLAGS += -lm +LDFLAGS += -L$(BSG_PLATFORM_PATH) +LDFLAGS += -T$(BLACKPARROT_SDK_DIR)/install/linker/riscv.ld +LDFLAGS += -Wl,--whole-archive -lbsgmc_cuda_legacy_pod_repl -lbsg_manycore_runtime -lbsg_manycore_regression -Wl,--no-whole-archive + +TEST_CSOURCES += $(filter %.c,$(TEST_SOURCES)) +TEST_CSOURCES += $(BSG_PLATFORM_PATH)/src/bsg_newlib_intf.c +TEST_CSOURCES += lfs.c +TEST_CXXSOURCES += $(filter %.cpp,$(TEST_SOURCES)) +TEST_OBJECTS += $(TEST_CXXSOURCES:.cpp=.o) +TEST_OBJECTS += $(TEST_CSOURCES:.c=.o) + +REGRESSION_LIBRARIES += $(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.a +REGRESSION_LIBRARIES += $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.a +REGRESSION_LIBRARIES += $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.a + +# 1 MB +DRAMFS_MKLFS ?= $(BLACKPARROT_SDK_DIR)/install/bin/dramfs_mklfs 128 8192 +lfs.c: + $(MAKE) $(BSG_MANYCORE_KERNELS) + -cp $(BSG_MANYCORE_KERNELS) $(notdir $(BSG_MANYCORE_KERNELS)) + $(DRAMFS_MKLFS) $(notdir $(BSG_MANYCORE_KERNELS)) > $@ + +loader.o: $(TEST_OBJECTS) $(REGRESSION_LIBRARIES) + $(CXX) -o $@ $(TEST_OBJECTS) $(LDFLAGS) + +.PHONY: platform.link.clean +platform.link.clean: + rm -rf loader.o + +link.clean: platform.link.clean + diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-ba.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-ba.c new file mode 100644 index 000000000..e083e7cee --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-ba.c @@ -0,0 +1,55 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Default definition for ARGP_PROGRAM_BUG_ADDRESS. + Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* If set by the user program, it should point to string that is the + bug-reporting address for the program. It will be printed by argp_help if + the ARGP_HELP_BUG_ADDR flag is set (as it is by various standard help + messages), embedded in a sentence that says something like `Report bugs to + ADDR.'. */ +const char *argp_program_bug_address; diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-eexst.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-eexst.c new file mode 100644 index 000000000..0e20f7ad7 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-eexst.c @@ -0,0 +1,61 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Default definition for ARGP_ERR_EXIT_STATUS + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +/* The exit status that argp will use when exiting due to a parsing error. + If not defined or set by the user program, this defaults to EX_USAGE from + . */ +error_t argp_err_exit_status = EX_USAGE; diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-fmtstream.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-fmtstream.c new file mode 100644 index 000000000..b4481f647 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-fmtstream.c @@ -0,0 +1,458 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Word-wrapping and line-truncating streams + Copyright (C) 1997, 1998, 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This package emulates glibc `line_wrap_stream' semantics for systems that + don't have that. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "argp-fmtstream.h" +#include "argp-namefrob.h" + +#ifndef ARGP_FMTSTREAM_USE_LINEWRAP + +#ifndef isblank +#define isblank(ch) ((ch)==' ' || (ch)=='\t') +#endif + +#if defined _LIBC && defined USE_IN_LIBIO +# include +# include +# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a) +#endif + +#define INIT_BUF_SIZE 200 +#define PRINTF_SIZE_GUESS 150 + +/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by + replacing the whitespace before them with a newline and WMARGIN spaces. + Otherwise, chars beyond RMARGIN are simply dropped until a newline. + Returns NULL if there was an error. */ +argp_fmtstream_t +__argp_make_fmtstream (FILE *stream, size_t lmargin, size_t rmargin, ssize_t wmargin) +{ + argp_fmtstream_t fs; + + fs = (struct argp_fmtstream *) malloc (sizeof (struct argp_fmtstream)); + if (fs != NULL) + { + fs->stream = stream; + + fs->lmargin = lmargin; + fs->rmargin = rmargin; + fs->wmargin = wmargin; + fs->point_col = 0; + fs->point_offs = 0; + + fs->buf = (char *) malloc (INIT_BUF_SIZE); + if (! fs->buf) + { + free (fs); + fs = 0; + } + else + { + fs->p = fs->buf; + fs->end = fs->buf + INIT_BUF_SIZE; + } + } + + return fs; +} +#ifdef weak_alias +weak_alias (__argp_make_fmtstream, argp_make_fmtstream) +#endif + +/* Flush FS to its stream, and free it (but don't close the stream). */ +void +__argp_fmtstream_free (argp_fmtstream_t fs) +{ + __argp_fmtstream_update (fs); + if (fs->p > fs->buf) + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + __fwprintf (fs->stream, L"%.*s", (int) (fs->p - fs->buf), fs->buf); + else +#endif + fwrite (fs->buf, 1, fs->p - fs->buf, fs->stream); + } + free (fs->buf); + free (fs); +} +#ifdef weak_alias +weak_alias (__argp_fmtstream_free, argp_fmtstream_free) +#endif + +/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the + end of its buffer. This code is mostly from glibc stdio/linewrap.c. */ +void +__argp_fmtstream_update (argp_fmtstream_t fs) +{ + char *buf, *nl; + size_t len; + + /* Scan the buffer for newlines. */ + buf = fs->buf + fs->point_offs; + while (buf < fs->p) + { + size_t r; + + if (fs->point_col == 0 && fs->lmargin != 0) + { + /* We are starting a new line. Print spaces to the left margin. */ + const size_t pad = fs->lmargin; + if (fs->p + pad < fs->end) + { + /* We can fit in them in the buffer by moving the + buffer text up and filling in the beginning. */ + memmove (buf + pad, buf, fs->p - buf); + fs->p += pad; /* Compensate for bigger buffer. */ + memset (buf, ' ', pad); /* Fill in the spaces. */ + buf += pad; /* Don't bother searching them. */ + } + else + { + /* No buffer space for spaces. Must flush. */ + size_t i; + for (i = 0; i < pad; i++) + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + putwc_unlocked (L' ', fs->stream); + else +#endif + putc_unlocked (' ', fs->stream); + } + } + fs->point_col = pad; + } + + len = fs->p - buf; + nl = memchr (buf, '\n', len); + + if (fs->point_col < 0) + fs->point_col = 0; + + if (!nl) + { + /* The buffer ends in a partial line. */ + + if (fs->point_col + len < fs->rmargin) + { + /* The remaining buffer text is a partial line and fits + within the maximum line width. Advance point for the + characters to be written and stop scanning. */ + fs->point_col += len; + break; + } + else + /* Set the end-of-line pointer for the code below to + the end of the buffer. */ + nl = fs->p; + } + else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin) + { + /* The buffer contains a full line that fits within the maximum + line width. Reset point and scan the next line. */ + fs->point_col = 0; + buf = nl + 1; + continue; + } + + /* This line is too long. */ + r = fs->rmargin - 1; + + if (fs->wmargin < 0) + { + /* Truncate the line by overwriting the excess with the + newline and anything after it in the buffer. */ + if (nl < fs->p) + { + memmove (buf + (r - fs->point_col), nl, fs->p - nl); + fs->p -= buf + (r - fs->point_col) - nl; + /* Reset point for the next line and start scanning it. */ + fs->point_col = 0; + buf += r + 1; /* Skip full line plus \n. */ + } + else + { + /* The buffer ends with a partial line that is beyond the + maximum line width. Advance point for the characters + written, and discard those past the max from the buffer. */ + fs->point_col += len; + fs->p -= fs->point_col - r; + break; + } + } + else + { + /* Do word wrap. Go to the column just past the maximum line + width and scan back for the beginning of the word there. + Then insert a line break. */ + + char *p, *nextline; + int i; + + p = buf + (r + 1 - fs->point_col); + while (p >= buf && !isblank (*p)) + --p; + nextline = p + 1; /* This will begin the next line. */ + + if (nextline > buf) + { + /* Swallow separating blanks. */ + if (p >= buf) + do + --p; + while (p >= buf && isblank (*p)); + nl = p + 1; /* The newline will replace the first blank. */ + } + else + { + /* A single word that is greater than the maximum line width. + Oh well. Put it on an overlong line by itself. */ + p = buf + (r + 1 - fs->point_col); + /* Find the end of the long word. */ + do + ++p; + while (p < nl && !isblank (*p)); + if (p == nl) + { + /* It already ends a line. No fussing required. */ + fs->point_col = 0; + buf = nl + 1; + continue; + } + /* We will move the newline to replace the first blank. */ + nl = p; + /* Swallow separating blanks. */ + do + ++p; + while (isblank (*p)); + /* The next line will start here. */ + nextline = p; + } + + /* Note: There are a bunch of tests below for + NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall + at the end of the buffer, and NEXTLINE is in fact empty (and so + we need not be careful to maintain its contents). */ + + if (nextline == buf + len + 1 + ? fs->end - nl < fs->wmargin + 1 + : nextline - (nl + 1) < fs->wmargin) + { + /* The margin needs more blanks than we removed. */ + if (fs->end - fs->p > fs->wmargin + 1) + /* Make some space for them. */ + { + size_t mv = fs->p - nextline; + memmove (nl + 1 + fs->wmargin, nextline, mv); + nextline = nl + 1 + fs->wmargin; + len = nextline + mv - buf; + *nl++ = '\n'; + } + else + /* Output the first line so we can use the space. */ + { +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + __fwprintf (fs->stream, L"%.*s\n", + (int) (nl - fs->buf), fs->buf); + else +#endif + { + if (nl > fs->buf) + fwrite (fs->buf, 1, nl - fs->buf, fs->stream); + putc_unlocked ('\n', fs->stream); + } + len += buf - fs->buf; + nl = buf = fs->buf; + } + } + else + /* We can fit the newline and blanks in before + the next word. */ + *nl++ = '\n'; + + if (nextline - nl >= fs->wmargin + || (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin)) + /* Add blanks up to the wrap margin column. */ + for (i = 0; i < fs->wmargin; ++i) + *nl++ = ' '; + else + for (i = 0; i < fs->wmargin; ++i) +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + putwc_unlocked (L' ', fs->stream); + else +#endif + putc_unlocked (' ', fs->stream); + + /* Copy the tail of the original buffer into the current buffer + position. */ + if (nl < nextline) + memmove (nl, nextline, buf + len - nextline); + len -= nextline - buf; + + /* Continue the scan on the remaining lines in the buffer. */ + buf = nl; + + /* Restore bufp to include all the remaining text. */ + fs->p = nl + len; + + /* Reset the counter of what has been output this line. If wmargin + is 0, we want to avoid the lmargin getting added, so we set + point_col to a magic value of -1 in that case. */ + fs->point_col = fs->wmargin ? fs->wmargin : -1; + } + } + + /* Remember that we've scanned as far as the end of the buffer. */ + fs->point_offs = fs->p - fs->buf; +} + +/* Ensure that FS has space for AMOUNT more bytes in its buffer, either by + growing the buffer, or by flushing it. True is returned iff we succeed. */ +int +__argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount) +{ + if ((size_t) (fs->end - fs->p) < amount) + { + ssize_t wrote; + + /* Flush FS's buffer. */ + __argp_fmtstream_update (fs); + +#ifdef USE_IN_LIBIO + if (_IO_fwide (fs->stream, 0) > 0) + { + __fwprintf (fs->stream, L"%.*s", (int) (fs->p - fs->buf), fs->buf); + wrote = fs->p - fs->buf; + } + else +#endif + wrote = fwrite (fs->buf, 1, fs->p - fs->buf, fs->stream); + if (wrote == fs->p - fs->buf) + { + fs->p = fs->buf; + fs->point_offs = 0; + } + else + { + fs->p -= wrote; + fs->point_offs -= wrote; + memmove (fs->buf, fs->buf + wrote, fs->p - fs->buf); + return 0; + } + + if ((size_t) (fs->end - fs->buf) < amount) + /* Gotta grow the buffer. */ + { + size_t new_size = fs->end - fs->buf + amount; + char *new_buf = realloc (fs->buf, new_size); + + if (! new_buf) + { + __set_errno (ENOMEM); + return 0; + } + + fs->buf = new_buf; + fs->end = new_buf + new_size; + fs->p = fs->buf; + } + } + + return 1; +} + +ssize_t +__argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...) +{ + int out; + size_t avail; + size_t size_guess = PRINTF_SIZE_GUESS; /* How much space to reserve. */ + + do + { + va_list args; + + if (! __argp_fmtstream_ensure (fs, size_guess)) + return -1; + + va_start (args, fmt); + avail = fs->end - fs->p; + out = __vsnprintf (fs->p, avail, fmt, args); + va_end (args); + if (out >= avail) + size_guess = out + 1; + } + while (out >= avail); + + fs->p += out; + + return out; +} +#ifdef weak_alias +weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf) +#endif + +#endif /* !ARGP_FMTSTREAM_USE_LINEWRAP */ diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-fs-xinl.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-fs-xinl.c new file mode 100644 index 000000000..910401859 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-fs-xinl.c @@ -0,0 +1,70 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Real definitions for extern inline functions in argp-fmtstream.h + Copyright (C) 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define ARGP_FS_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ 1 +#include "argp-fmtstream.h" + +/* Add weak aliases. */ +#if _LIBC - 0 && !defined (ARGP_FMTSTREAM_USE_LINEWRAP) && defined (weak_alias) + +weak_alias (__argp_fmtstream_putc, argp_fmtstream_putc) +weak_alias (__argp_fmtstream_puts, argp_fmtstream_puts) +weak_alias (__argp_fmtstream_write, argp_fmtstream_write) +weak_alias (__argp_fmtstream_set_lmargin, argp_fmtstream_set_lmargin) +weak_alias (__argp_fmtstream_set_rmargin, argp_fmtstream_set_rmargin) +weak_alias (__argp_fmtstream_set_wmargin, argp_fmtstream_set_wmargin) +weak_alias (__argp_fmtstream_point, argp_fmtstream_point) + +#endif diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-help.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-help.c new file mode 100644 index 000000000..839aa1850 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-help.c @@ -0,0 +1,1891 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Hierarchial argument parsing help output + Copyright (C) 1995-2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifndef alloca +# ifdef __GNUC__ +# define alloca __builtin_alloca +# define HAVE_ALLOCA 1 +# else +# if defined HAVE_ALLOCA_H || defined _LIBC +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_IN_LIBIO +# include +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. */ +# if defined HAVE_LIBINTL_H || defined _LIBC +# include +# ifdef _LIBC +# undef dgettext +# define dgettext(domain, msgid) __dcgettext (domain, msgid, LC_MESSAGES) +# endif +# else +# define dgettext(domain, msgid) (msgid) +# endif +#endif + +#include +#include +#include + +/* User-selectable (using an environment variable) formatting parameters. + + These may be specified in an environment variable called `ARGP_HELP_FMT', + with a contents like: VAR1=VAL1,VAR2=VAL2,BOOLVAR2,no-BOOLVAR2 + Where VALn must be a positive integer. The list of variables is in the + UPARAM_NAMES vector, below. */ + +/* Default parameters. */ +#define DUP_ARGS 0 /* True if option argument can be duplicated. */ +#define DUP_ARGS_NOTE 1 /* True to print a note about duplicate args. */ +#define SHORT_OPT_COL 2 /* column in which short options start */ +#define LONG_OPT_COL 6 /* column in which long options start */ +#define DOC_OPT_COL 2 /* column in which doc options start */ +#define OPT_DOC_COL 29 /* column in which option text starts */ +#define HEADER_COL 1 /* column in which group headers are printed */ +#define USAGE_INDENT 12 /* indentation of wrapped usage lines */ +#define RMARGIN 79 /* right margin used for wrapping */ + +/* User-selectable (using an environment variable) formatting parameters. + They must all be of type `int' for the parsing code to work. */ +struct uparams +{ + /* If true, arguments for an option are shown with both short and long + options, even when a given option has both, e.g. `-x ARG, --longx=ARG'. + If false, then if an option has both, the argument is only shown with + the long one, e.g., `-x, --longx=ARG', and a message indicating that + this really means both is printed below the options. */ + int dup_args; + + /* This is true if when DUP_ARGS is false, and some duplicate arguments have + been suppressed, an explanatory message should be printed. */ + int dup_args_note; + + /* Various output columns. */ + int short_opt_col; + int long_opt_col; + int doc_opt_col; + int opt_doc_col; + int header_col; + int usage_indent; + int rmargin; + + int valid; /* True when the values in here are valid. */ +}; + +/* This is a global variable, as user options are only ever read once. */ +static struct uparams uparams = { + DUP_ARGS, DUP_ARGS_NOTE, + SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL, + USAGE_INDENT, RMARGIN, + 0 +}; + +/* A particular uparam, and what the user name is. */ +struct uparam_name +{ + const char *name; /* User name. */ + int is_bool; /* Whether it's `boolean'. */ + size_t uparams_offs; /* Location of the (int) field in UPARAMS. */ +}; + +/* The name-field mappings we know about. */ +static const struct uparam_name uparam_names[] = +{ + { "dup-args", 1, offsetof (struct uparams, dup_args) }, + { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) }, + { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) }, + { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) }, + { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) }, + { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) }, + { "header-col", 0, offsetof (struct uparams, header_col) }, + { "usage-indent", 0, offsetof (struct uparams, usage_indent) }, + { "rmargin", 0, offsetof (struct uparams, rmargin) }, + { 0 } +}; + +/* Read user options from the environment, and fill in UPARAMS appropiately. */ +static void +fill_in_uparams (const struct argp_state *state) +{ + const char *var = getenv ("ARGP_HELP_FMT"); + +#define SKIPWS(p) do { while (isspace (*p)) p++; } while (0); + + if (var) + /* Parse var. */ + while (*var) + { + SKIPWS (var); + + if (isalpha (*var)) + { + size_t var_len; + const struct uparam_name *un; + int unspec = 0, val = 0; + const char *arg = var; + + while (isalnum (*arg) || *arg == '-' || *arg == '_') + arg++; + var_len = arg - var; + + SKIPWS (arg); + + if (*arg == '\0' || *arg == ',') + unspec = 1; + else if (*arg == '=') + { + arg++; + SKIPWS (arg); + } + + if (unspec) + { + if (var[0] == 'n' && var[1] == 'o' && var[2] == '-') + { + val = 0; + var += 3; + var_len -= 3; + } + else + val = 1; + } + else if (isdigit (*arg)) + { + val = atoi (arg); + while (isdigit (*arg)) + arg++; + SKIPWS (arg); + } + + for (un = uparam_names; un->name; un++) + if (strlen (un->name) == var_len + && strncmp (var, un->name, var_len) == 0) + { + if (unspec && !un->is_bool) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ + %.*s: ARGP_HELP_FMT parameter requires a value"), + (int) var_len, var); + else + *(int *)((char *)&uparams + un->uparams_offs) = val; + break; + } + if (! un->name) + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, "\ + %.*s: Unknown ARGP_HELP_FMT parameter"), + (int) var_len, var); + + var = arg; + if (*var == ',') + var++; + } + else if (*var) + { + __argp_failure (state, 0, 0, + dgettext (state->root_argp->argp_domain, + "Garbage in ARGP_HELP_FMT: %s"), var); + break; + } + } +} + +/* Returns true if OPT hasn't been marked invisible. Visibility only affects + whether OPT is displayed or used in sorting, not option shadowing. */ +#define ovisible(opt) (! ((opt)->flags & OPTION_HIDDEN)) + +/* Returns true if OPT is an alias for an earlier option. */ +#define oalias(opt) ((opt)->flags & OPTION_ALIAS) + +/* Returns true if OPT is an documentation-only entry. */ +#define odoc(opt) ((opt)->flags & OPTION_DOC) + +/* Returns true if OPT is the end-of-list marker for a list of options. */ +#define oend(opt) __option_is_end (opt) + +/* Returns true if OPT has a short option. */ +#define oshort(opt) __option_is_short (opt) + +/* + The help format for a particular option is like: + + -xARG, -yARG, --long1=ARG, --long2=ARG Documentation... + + Where ARG will be omitted if there's no argument, for this option, or + will be surrounded by "[" and "]" appropiately if the argument is + optional. The documentation string is word-wrapped appropiately, and if + the list of options is long enough, it will be started on a separate line. + If there are no short options for a given option, the first long option is + indented slighly in a way that's supposed to make most long options appear + to be in a separate column. + + For example, the following output (from ps): + + -p PID, --pid=PID List the process PID + --pgrp=PGRP List processes in the process group PGRP + -P, -x, --no-parent Include processes without parents + -Q, --all-fields Don't elide unusable fields (normally if there's + some reason ps can't print a field for any + process, it's removed from the output entirely) + -r, --reverse, --gratuitously-long-reverse-option + Reverse the order of any sort + --session[=SID] Add the processes from the session SID (which + defaults to the sid of the current process) + + Here are some more options: + -f ZOT, --foonly=ZOT Glork a foonly + -z, --zaza Snit a zar + + -?, --help Give this help list + --usage Give a short usage message + -V, --version Print program version + + The struct argp_option array for the above could look like: + + { + {"pid", 'p', "PID", 0, "List the process PID"}, + {"pgrp", OPT_PGRP, "PGRP", 0, "List processes in the process group PGRP"}, + {"no-parent", 'P', 0, 0, "Include processes without parents"}, + {0, 'x', 0, OPTION_ALIAS}, + {"all-fields",'Q', 0, 0, "Don't elide unusable fields (normally" + " if there's some reason ps can't" + " print a field for any process, it's" + " removed from the output entirely)" }, + {"reverse", 'r', 0, 0, "Reverse the order of any sort"}, + {"gratuitously-long-reverse-option", 0, 0, OPTION_ALIAS}, + {"session", OPT_SESS, "SID", OPTION_ARG_OPTIONAL, + "Add the processes from the session" + " SID (which defaults to the sid of" + " the current process)" }, + + {0,0,0,0, "Here are some more options:"}, + {"foonly", 'f', "ZOT", 0, "Glork a foonly"}, + {"zaza", 'z', 0, 0, "Snit a zar"}, + + {0} + } + + Note that the last three options are automatically supplied by argp_parse, + unless you tell it not to with ARGP_NO_HELP. + +*/ + +/* Returns true if CH occurs between BEG and END. */ +static int +find_char (char ch, char *beg, char *end) +{ + while (beg < end) + if (*beg == ch) + return 1; + else + beg++; + return 0; +} + +struct hol_cluster; /* fwd decl */ + +struct hol_entry +{ + /* First option. */ + const struct argp_option *opt; + /* Number of options (including aliases). */ + unsigned num; + + /* A pointers into the HOL's short_options field, to the first short option + letter for this entry. The order of the characters following this point + corresponds to the order of options pointed to by OPT, and there are at + most NUM. A short option recorded in a option following OPT is only + valid if it occurs in the right place in SHORT_OPTIONS (otherwise it's + probably been shadowed by some other entry). */ + char *short_options; + + /* Entries are sorted by their group first, in the order: + 1, 2, ..., n, 0, -m, ..., -2, -1 + and then alphabetically within each group. The default is 0. */ + int group; + + /* The cluster of options this entry belongs to, or 0 if none. */ + struct hol_cluster *cluster; + + /* The argp from which this option came. */ + const struct argp *argp; +}; + +/* A cluster of entries to reflect the argp tree structure. */ +struct hol_cluster +{ + /* A descriptive header printed before options in this cluster. */ + const char *header; + + /* Used to order clusters within the same group with the same parent, + according to the order in which they occurred in the parent argp's child + list. */ + int index; + + /* How to sort this cluster with respect to options and other clusters at the + same depth (clusters always follow options in the same group). */ + int group; + + /* The cluster to which this cluster belongs, or 0 if it's at the base + level. */ + struct hol_cluster *parent; + + /* The argp from which this cluster is (eventually) derived. */ + const struct argp *argp; + + /* The distance this cluster is from the root. */ + int depth; + + /* Clusters in a given hol are kept in a linked list, to make freeing them + possible. */ + struct hol_cluster *next; +}; + +/* A list of options for help. */ +struct hol +{ + /* An array of hol_entry's. */ + struct hol_entry *entries; + /* The number of entries in this hol. If this field is zero, the others + are undefined. */ + unsigned num_entries; + + /* A string containing all short options in this HOL. Each entry contains + pointers into this string, so the order can't be messed with blindly. */ + char *short_options; + + /* Clusters of entries in this hol. */ + struct hol_cluster *clusters; +}; + +/* Create a struct hol from the options in ARGP. CLUSTER is the + hol_cluster in which these entries occur, or 0, if at the root. */ +static struct hol * +make_hol (const struct argp *argp, struct hol_cluster *cluster) +{ + char *so; + const struct argp_option *o; + const struct argp_option *opts = argp->options; + struct hol_entry *entry; + unsigned num_short_options = 0; + struct hol *hol = malloc (sizeof (struct hol)); + + assert (hol); + + hol->num_entries = 0; + hol->clusters = 0; + + if (opts) + { + int cur_group = 0; + + /* The first option must not be an alias. */ + assert (! oalias (opts)); + + /* Calculate the space needed. */ + for (o = opts; ! oend (o); o++) + { + if (! oalias (o)) + hol->num_entries++; + if (oshort (o)) + num_short_options++; /* This is an upper bound. */ + } + + hol->entries = malloc (sizeof (struct hol_entry) * hol->num_entries); + hol->short_options = malloc (num_short_options + 1); + + assert (hol->entries && hol->short_options); + + /* Fill in the entries. */ + so = hol->short_options; + for (o = opts, entry = hol->entries; ! oend (o); entry++) + { + entry->opt = o; + entry->num = 0; + entry->short_options = so; + entry->group = cur_group = + o->group + ? o->group + : ((!o->name && !o->key) + ? cur_group + 1 + : cur_group); + entry->cluster = cluster; + entry->argp = argp; + + do + { + entry->num++; + if (oshort (o) && ! find_char (o->key, hol->short_options, so)) + /* O has a valid short option which hasn't already been used.*/ + *so++ = o->key; + o++; + } + while (! oend (o) && oalias (o)); + } + *so = '\0'; /* null terminated so we can find the length */ + } + + return hol; +} + +/* Add a new cluster to HOL, with the given GROUP and HEADER (taken from the + associated argp child list entry), INDEX, and PARENT, and return a pointer + to it. ARGP is the argp that this cluster results from. */ +static struct hol_cluster * +hol_add_cluster (struct hol *hol, int group, const char *header, int index, + struct hol_cluster *parent, const struct argp *argp) +{ + struct hol_cluster *cl = malloc (sizeof (struct hol_cluster)); + if (cl) + { + cl->group = group; + cl->header = header; + + cl->index = index; + cl->parent = parent; + cl->argp = argp; + cl->depth = parent ? parent->depth + 1 : 0; + + cl->next = hol->clusters; + hol->clusters = cl; + } + return cl; +} + +/* Free HOL and any resources it uses. */ +static void +hol_free (struct hol *hol) +{ + struct hol_cluster *cl = hol->clusters; + + while (cl) + { + struct hol_cluster *next = cl->next; + free (cl); + cl = next; + } + + if (hol->num_entries > 0) + { + free (hol->entries); + free (hol->short_options); + } + + free (hol); +} + +static inline int +hol_entry_short_iterate (const struct hol_entry *entry, + int (*func)(const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie), + const char *domain, void *cookie) +{ + unsigned nopts; + int val = 0; + const struct argp_option *opt, *real = entry->opt; + char *so = entry->short_options; + + for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) + if (oshort (opt) && *so == opt->key) + { + if (!oalias (opt)) + real = opt; + if (ovisible (opt)) + val = (*func)(opt, real, domain, cookie); + so++; + } + + return val; +} + +static inline int +hol_entry_long_iterate (const struct hol_entry *entry, + int (*func)(const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie), + const char *domain, void *cookie) +{ + unsigned nopts; + int val = 0; + const struct argp_option *opt, *real = entry->opt; + + for (opt = real, nopts = entry->num; nopts > 0 && !val; opt++, nopts--) + if (opt->name) + { + if (!oalias (opt)) + real = opt; + if (ovisible (opt)) + val = (*func)(opt, real, domain, cookie); + } + + return val; +} + +/* Iterator that returns true for the first short option. */ +static inline int +until_short (const struct argp_option *opt, const struct argp_option *real, + const char *domain, void *cookie) +{ + return oshort (opt) ? opt->key : 0; +} + +/* Returns the first valid short option in ENTRY, or 0 if there is none. */ +static char +hol_entry_first_short (const struct hol_entry *entry) +{ + return hol_entry_short_iterate (entry, until_short, + entry->argp->argp_domain, 0); +} + +/* Returns the first valid long option in ENTRY, or 0 if there is none. */ +static const char * +hol_entry_first_long (const struct hol_entry *entry) +{ + const struct argp_option *opt; + unsigned num; + for (opt = entry->opt, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + return opt->name; + return 0; +} + +/* Returns the entry in HOL with the long option name NAME, or 0 if there is + none. */ +static struct hol_entry * +hol_find_entry (struct hol *hol, const char *name) +{ + struct hol_entry *entry = hol->entries; + unsigned num_entries = hol->num_entries; + + while (num_entries-- > 0) + { + const struct argp_option *opt = entry->opt; + unsigned num_opts = entry->num; + + while (num_opts-- > 0) + if (opt->name && ovisible (opt) && strcmp (opt->name, name) == 0) + return entry; + else + opt++; + + entry++; + } + + return 0; +} + +/* If an entry with the long option NAME occurs in HOL, set it's special + sort position to GROUP. */ +static void +hol_set_group (struct hol *hol, const char *name, int group) +{ + struct hol_entry *entry = hol_find_entry (hol, name); + if (entry) + entry->group = group; +} + +/* Order by group: 0, 1, 2, ..., n, -m, ..., -2, -1. + EQ is what to return if GROUP1 and GROUP2 are the same. */ +static int +group_cmp (int group1, int group2, int eq) +{ + if (group1 == group2) + return eq; + else if ((group1 < 0 && group2 < 0) || (group1 >= 0 && group2 >= 0)) + return group1 - group2; + else + return group2 - group1; +} + +/* Compare clusters CL1 & CL2 by the order that they should appear in + output. */ +static int +hol_cluster_cmp (const struct hol_cluster *cl1, const struct hol_cluster *cl2) +{ + /* If one cluster is deeper than the other, use its ancestor at the same + level, so that finding the common ancestor is straightforward. */ + while (cl1->depth < cl2->depth) + cl1 = cl1->parent; + while (cl2->depth < cl1->depth) + cl2 = cl2->parent; + + /* Now reduce both clusters to their ancestors at the point where both have + a common parent; these can be directly compared. */ + while (cl1->parent != cl2->parent) + cl1 = cl1->parent, cl2 = cl2->parent; + + return group_cmp (cl1->group, cl2->group, cl2->index - cl1->index); +} + +/* Return the ancestor of CL that's just below the root (i.e., has a parent + of 0). */ +static struct hol_cluster * +hol_cluster_base (struct hol_cluster *cl) +{ + while (cl->parent) + cl = cl->parent; + return cl; +} + +/* Return true if CL1 is a child of CL2. */ +static int +hol_cluster_is_child (const struct hol_cluster *cl1, + const struct hol_cluster *cl2) +{ + while (cl1 && cl1 != cl2) + cl1 = cl1->parent; + return cl1 == cl2; +} + +/* Given the name of a OPTION_DOC option, modifies NAME to start at the tail + that should be used for comparisons, and returns true iff it should be + treated as a non-option. */ +static int +canon_doc_option (const char **name) +{ + int non_opt; + /* Skip initial whitespace. */ + while (isspace (**name)) + (*name)++; + /* Decide whether this looks like an option (leading `-') or not. */ + non_opt = (**name != '-'); + /* Skip until part of name used for sorting. */ + while (**name && !isalnum (**name)) + (*name)++; + return non_opt; +} + +/* Order ENTRY1 & ENTRY2 by the order which they should appear in a help + listing. */ +static int +hol_entry_cmp (const struct hol_entry *entry1, + const struct hol_entry *entry2) +{ + /* The group numbers by which the entries should be ordered; if either is + in a cluster, then this is just the group within the cluster. */ + int group1 = entry1->group, group2 = entry2->group; + + if (entry1->cluster != entry2->cluster) + { + /* The entries are not within the same cluster, so we can't compare them + directly, we have to use the appropiate clustering level too. */ + if (! entry1->cluster) + /* ENTRY1 is at the `base level', not in a cluster, so we have to + compare it's group number with that of the base cluster in which + ENTRY2 resides. Note that if they're in the same group, the + clustered option always comes laster. */ + return group_cmp (group1, hol_cluster_base (entry2->cluster)->group, -1); + else if (! entry2->cluster) + /* Likewise, but ENTRY2's not in a cluster. */ + return group_cmp (hol_cluster_base (entry1->cluster)->group, group2, 1); + else + /* Both entries are in clusters, we can just compare the clusters. */ + return hol_cluster_cmp (entry1->cluster, entry2->cluster); + } + else if (group1 == group2) + /* The entries are both in the same cluster and group, so compare them + alphabetically. */ + { + int short1 = hol_entry_first_short (entry1); + int short2 = hol_entry_first_short (entry2); + int doc1 = odoc (entry1->opt); + int doc2 = odoc (entry2->opt); + const char *long1 = hol_entry_first_long (entry1); + const char *long2 = hol_entry_first_long (entry2); + + if (doc1) + doc1 = canon_doc_option (&long1); + if (doc2) + doc2 = canon_doc_option (&long2); + + if (doc1 != doc2) + /* `documentation' options always follow normal options (or + documentation options that *look* like normal options). */ + return doc1 - doc2; + else if (!short1 && !short2 && long1 && long2) + /* Only long options. */ + return __strcasecmp (long1, long2); + else + /* Compare short/short, long/short, short/long, using the first + character of long options. Entries without *any* valid + options (such as options with OPTION_HIDDEN set) will be put + first, but as they're not displayed, it doesn't matter where + they are. */ + { + char first1 = short1 ? short1 : long1 ? *long1 : 0; + char first2 = short2 ? short2 : long2 ? *long2 : 0; +#ifdef _tolower + int lower_cmp = _tolower (first1) - _tolower (first2); +#else + int lower_cmp = tolower (first1) - tolower (first2); +#endif + /* Compare ignoring case, except when the options are both the + same letter, in which case lower-case always comes first. */ + return lower_cmp ? lower_cmp : first2 - first1; + } + } + else + /* Within the same cluster, but not the same group, so just compare + groups. */ + return group_cmp (group1, group2, 0); +} + +/* Version of hol_entry_cmp with correct signature for qsort. */ +static int +hol_entry_qcmp (const void *entry1_v, const void *entry2_v) +{ + return hol_entry_cmp (entry1_v, entry2_v); +} + +/* Sort HOL by group and alphabetically by option name (with short options + taking precedence over long). Since the sorting is for display purposes + only, the shadowing of options isn't effected. */ +static void +hol_sort (struct hol *hol) +{ + if (hol->num_entries > 0) + qsort (hol->entries, hol->num_entries, sizeof (struct hol_entry), + hol_entry_qcmp); +} + +/* Append MORE to HOL, destroying MORE in the process. Options in HOL shadow + any in MORE with the same name. */ +static void +hol_append (struct hol *hol, struct hol *more) +{ + struct hol_cluster **cl_end = &hol->clusters; + char *tmp; + + /* Steal MORE's cluster list, and add it to the end of HOL's. */ + while (*cl_end) + cl_end = &(*cl_end)->next; + *cl_end = more->clusters; + more->clusters = 0; + + /* Merge entries. */ + if (more->num_entries > 0) + { + if (hol->num_entries == 0) + { + hol->num_entries = more->num_entries; + hol->entries = more->entries; + hol->short_options = more->short_options; + more->num_entries = 0; /* Mark MORE's fields as invalid. */ + } + else + /* Append the entries in MORE to those in HOL, taking care to only add + non-shadowed SHORT_OPTIONS values. */ + { + unsigned left; + char *so, *more_so; + struct hol_entry *e; + unsigned num_entries = hol->num_entries + more->num_entries; + struct hol_entry *entries = + malloc (num_entries * sizeof (struct hol_entry)); + unsigned hol_so_len = strlen (hol->short_options); + char *short_options = + malloc (hol_so_len + strlen (more->short_options) + 1); + + tmp = memcpy (entries, hol->entries, + hol->num_entries * sizeof (struct hol_entry)); + tmp += hol->num_entries * sizeof (struct hol_entry); + memcpy (tmp, + more->entries, + more->num_entries * sizeof (struct hol_entry)); + + memcpy (short_options, hol->short_options, hol_so_len); + + /* Fix up the short options pointers from HOL. */ + for (e = entries, left = hol->num_entries; left > 0; e++, left--) + e->short_options += (short_options - hol->short_options); + + /* Now add the short options from MORE, fixing up its entries + too. */ + so = short_options + hol_so_len; + more_so = more->short_options; + for (left = more->num_entries; left > 0; e++, left--) + { + int opts_left; + const struct argp_option *opt; + + e->short_options = so; + + for (opts_left = e->num, opt = e->opt; opts_left; opt++, opts_left--) + { + int ch = *more_so; + if (oshort (opt) && ch == opt->key) + /* The next short option in MORE_SO, CH, is from OPT. */ + { + if (! find_char (ch, short_options, + short_options + hol_so_len)) + /* The short option CH isn't shadowed by HOL's options, + so add it to the sum. */ + *so++ = ch; + more_so++; + } + } + } + + *so = '\0'; + + free (hol->entries); + free (hol->short_options); + + hol->entries = entries; + hol->num_entries = num_entries; + hol->short_options = short_options; + } + } + + hol_free (more); +} + +/* Inserts enough spaces to make sure STREAM is at column COL. */ +static void +indent_to (argp_fmtstream_t stream, unsigned col) +{ + int needed = col - __argp_fmtstream_point (stream); + while (needed-- > 0) + __argp_fmtstream_putc (stream, ' '); +} + +/* Output to STREAM either a space, or a newline if there isn't room for at + least ENSURE characters before the right margin. */ +static void +space (argp_fmtstream_t stream, size_t ensure) +{ + if (__argp_fmtstream_point (stream) + ensure + >= __argp_fmtstream_rmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + else + __argp_fmtstream_putc (stream, ' '); +} + +/* If the option REAL has an argument, we print it in using the printf + format REQ_FMT or OPT_FMT depending on whether it's a required or + optional argument. */ +static void +arg (const struct argp_option *real, const char *req_fmt, const char *opt_fmt, + const char *domain, argp_fmtstream_t stream) +{ + if (real->arg) + { + if (real->flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, opt_fmt, + dgettext (domain, real->arg)); + else + __argp_fmtstream_printf (stream, req_fmt, + dgettext (domain, real->arg)); + } +} + +/* Helper functions for hol_entry_help. */ + +/* State used during the execution of hol_help. */ +struct hol_help_state +{ + /* PREV_ENTRY should contain the previous entry printed, or 0. */ + struct hol_entry *prev_entry; + + /* If an entry is in a different group from the previous one, and SEP_GROUPS + is true, then a blank line will be printed before any output. */ + int sep_groups; + + /* True if a duplicate option argument was suppressed (only ever set if + UPARAMS.dup_args is false). */ + int suppressed_dup_arg; +}; + +/* Some state used while printing a help entry (used to communicate with + helper functions). See the doc for hol_entry_help for more info, as most + of the fields are copied from its arguments. */ +struct pentry_state +{ + const struct hol_entry *entry; + argp_fmtstream_t stream; + struct hol_help_state *hhstate; + + /* True if nothing's been printed so far. */ + int first; + + /* If non-zero, the state that was used to print this help. */ + const struct argp_state *state; +}; + +/* If a user doc filter should be applied to DOC, do so. */ +static const char * +filter_doc (const char *doc, int key, const struct argp *argp, + const struct argp_state *state) +{ + if (argp->help_filter) + /* We must apply a user filter to this output. */ + { + void *input = __argp_input (argp, state); + return (*argp->help_filter) (key, doc, input); + } + else + /* No filter. */ + return doc; +} + +/* Prints STR as a header line, with the margin lines set appropiately, and + notes the fact that groups should be separated with a blank line. ARGP is + the argp that should dictate any user doc filtering to take place. Note + that the previous wrap margin isn't restored, but the left margin is reset + to 0. */ +static void +print_header (const char *str, const struct argp *argp, + struct pentry_state *pest) +{ + const char *tstr = dgettext (argp->argp_domain, str); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_HEADER, argp, pest->state); + + if (fstr) + { + if (*fstr) + { + if (pest->hhstate->prev_entry) + /* Precede with a blank line. */ + __argp_fmtstream_putc (pest->stream, '\n'); + indent_to (pest->stream, uparams.header_col); + __argp_fmtstream_set_lmargin (pest->stream, uparams.header_col); + __argp_fmtstream_set_wmargin (pest->stream, uparams.header_col); + __argp_fmtstream_puts (pest->stream, fstr); + __argp_fmtstream_set_lmargin (pest->stream, 0); + __argp_fmtstream_putc (pest->stream, '\n'); + } + + pest->hhstate->sep_groups = 1; /* Separate subsequent groups. */ + } + + if (fstr != tstr) + free ((char *) fstr); +} + +/* Inserts a comma if this isn't the first item on the line, and then makes + sure we're at least to column COL. If this *is* the first item on a line, + prints any pending whitespace/headers that should precede this line. Also + clears FIRST. */ +static void +comma (unsigned col, struct pentry_state *pest) +{ + if (pest->first) + { + const struct hol_entry *pe = pest->hhstate->prev_entry; + const struct hol_cluster *cl = pest->entry->cluster; + + if (pest->hhstate->sep_groups && pe && pest->entry->group != pe->group) + __argp_fmtstream_putc (pest->stream, '\n'); + + if (cl && cl->header && *cl->header + && (!pe + || (pe->cluster != cl + && !hol_cluster_is_child (pe->cluster, cl)))) + /* If we're changing clusters, then this must be the start of the + ENTRY's cluster unless that is an ancestor of the previous one + (in which case we had just popped into a sub-cluster for a bit). + If so, then print the cluster's header line. */ + { + int old_wm = __argp_fmtstream_wmargin (pest->stream); + print_header (cl->header, cl->argp, pest); + __argp_fmtstream_set_wmargin (pest->stream, old_wm); + } + + pest->first = 0; + } + else + __argp_fmtstream_puts (pest->stream, ", "); + + indent_to (pest->stream, col); +} + +/* Print help for ENTRY to STREAM. */ +static void +hol_entry_help (struct hol_entry *entry, const struct argp_state *state, + argp_fmtstream_t stream, struct hol_help_state *hhstate) +{ + unsigned num; + const struct argp_option *real = entry->opt, *opt; + char *so = entry->short_options; + int have_long_opt = 0; /* We have any long options. */ + /* Saved margins. */ + int old_lm = __argp_fmtstream_set_lmargin (stream, 0); + int old_wm = __argp_fmtstream_wmargin (stream); + /* PEST is a state block holding some of our variables that we'd like to + share with helper functions. */ + struct pentry_state pest = { entry, stream, hhstate, 1, state }; + + if (! odoc (real)) + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + have_long_opt = 1; + break; + } + + /* First emit short options. */ + __argp_fmtstream_set_wmargin (stream, uparams.short_opt_col); /* For truly bizarre cases. */ + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (oshort (opt) && opt->key == *so) + /* OPT has a valid (non shadowed) short option. */ + { + if (ovisible (opt)) + { + comma (uparams.short_opt_col, &pest); + __argp_fmtstream_putc (stream, '-'); + __argp_fmtstream_putc (stream, *so); + if (!have_long_opt || uparams.dup_args) + arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; + } + so++; + } + + /* Now, long options. */ + if (odoc (real)) + /* A `documentation' option. */ + { + __argp_fmtstream_set_wmargin (stream, uparams.doc_opt_col); + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + comma (uparams.doc_opt_col, &pest); + /* Calling gettext here isn't quite right, since sorting will + have been done on the original; but documentation options + should be pretty rare anyway... */ + __argp_fmtstream_puts (stream, + dgettext (state->root_argp->argp_domain, + opt->name)); + } + } + else + /* A real long option. */ + { + int first_long_opt = 1; + + __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col); + for (opt = real, num = entry->num; num > 0; opt++, num--) + if (opt->name && ovisible (opt)) + { + comma (uparams.long_opt_col, &pest); + __argp_fmtstream_printf (stream, "--%s", opt->name); + if (first_long_opt || uparams.dup_args) + arg (real, "=%s", "[=%s]", state->root_argp->argp_domain, stream); + else if (real->arg) + hhstate->suppressed_dup_arg = 1; + } + } + + /* Next, documentation strings. */ + __argp_fmtstream_set_lmargin (stream, 0); + + if (pest.first) + { + /* Didn't print any switches, what's up? */ + if (!oshort (real) && !real->name) + /* This is a group header, print it nicely. */ + print_header (real->doc, entry->argp, &pest); + else + /* Just a totally shadowed option or null header; print nothing. */ + goto cleanup; /* Just return, after cleaning up. */ + } + else + { + const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain, + real->doc) : 0; + const char *fstr = filter_doc (tstr, real->key, entry->argp, state); + if (fstr && *fstr) + { + unsigned int col = __argp_fmtstream_point (stream); + + __argp_fmtstream_set_lmargin (stream, uparams.opt_doc_col); + __argp_fmtstream_set_wmargin (stream, uparams.opt_doc_col); + + if (col > (unsigned int) (uparams.opt_doc_col + 3)) + __argp_fmtstream_putc (stream, '\n'); + else if (col >= (unsigned int) uparams.opt_doc_col) + __argp_fmtstream_puts (stream, " "); + else + indent_to (stream, uparams.opt_doc_col); + + __argp_fmtstream_puts (stream, fstr); + } + if (fstr && fstr != tstr) + free ((char *) fstr); + + /* Reset the left margin. */ + __argp_fmtstream_set_lmargin (stream, 0); + __argp_fmtstream_putc (stream, '\n'); + } + + hhstate->prev_entry = entry; + +cleanup: + __argp_fmtstream_set_lmargin (stream, old_lm); + __argp_fmtstream_set_wmargin (stream, old_wm); +} + +/* Output a long help message about the options in HOL to STREAM. */ +static void +hol_help (struct hol *hol, const struct argp_state *state, + argp_fmtstream_t stream) +{ + unsigned num; + struct hol_entry *entry; + struct hol_help_state hhstate = { 0, 0, 0 }; + + for (entry = hol->entries, num = hol->num_entries; num > 0; entry++, num--) + hol_entry_help (entry, state, stream, &hhstate); + + if (hhstate.suppressed_dup_arg && uparams.dup_args_note) + { + const char *tstr = dgettext (state->root_argp->argp_domain, "\ + Mandatory or optional arguments to long options are also mandatory or \ + optional for any corresponding short options."); + const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE, + state ? state->root_argp : 0, state); + if (fstr && *fstr) + { + __argp_fmtstream_putc (stream, '\n'); + __argp_fmtstream_puts (stream, fstr); + __argp_fmtstream_putc (stream, '\n'); + } + if (fstr && fstr != tstr) + free ((char *) fstr); + } +} + +/* Helper functions for hol_usage. */ + +/* If OPT is a short option without an arg, append its key to the string + pointer pointer to by COOKIE, and advance the pointer. */ +static int +add_argless_short_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + char **snao_end = cookie; + if (!(opt->arg || real->arg) + && !((opt->flags | real->flags) & OPTION_NO_USAGE)) + *(*snao_end)++ = opt->key; + return 0; +} + +/* If OPT is a short option with an arg, output a usage entry for it to the + stream pointed at by COOKIE. */ +static int +usage_argful_short_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + argp_fmtstream_t stream = cookie; + const char *arg = opt->arg; + int flags = opt->flags | real->flags; + + if (! arg) + arg = real->arg; + + if (arg && !(flags & OPTION_NO_USAGE)) + { + arg = dgettext (domain, arg); + + if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [-%c[%s]]", opt->key, arg); + else + { + /* Manually do line wrapping so that it (probably) won't + get wrapped at the embedded space. */ + space (stream, 6 + strlen (arg)); + __argp_fmtstream_printf (stream, "[-%c %s]", opt->key, arg); + } + } + + return 0; +} + +/* Output a usage entry for the long option opt to the stream pointed at by + COOKIE. */ +static int +usage_long_opt (const struct argp_option *opt, + const struct argp_option *real, + const char *domain, void *cookie) +{ + argp_fmtstream_t stream = cookie; + const char *arg = opt->arg; + int flags = opt->flags | real->flags; + + if (! arg) + arg = real->arg; + + if (! (flags & OPTION_NO_USAGE)) + { + if (arg) + { + arg = dgettext (domain, arg); + if (flags & OPTION_ARG_OPTIONAL) + __argp_fmtstream_printf (stream, " [--%s[=%s]]", opt->name, arg); + else + __argp_fmtstream_printf (stream, " [--%s=%s]", opt->name, arg); + } + else + __argp_fmtstream_printf (stream, " [--%s]", opt->name); + } + + return 0; +} + +/* Print a short usage description for the arguments in HOL to STREAM. */ +static void +hol_usage (struct hol *hol, argp_fmtstream_t stream) +{ + if (hol->num_entries > 0) + { + unsigned nentries; + struct hol_entry *entry; + char *short_no_arg_opts = alloca (strlen (hol->short_options) + 1); + char *snao_end = short_no_arg_opts; + + /* First we put a list of short options without arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_short_iterate (entry, add_argless_short_opt, + entry->argp->argp_domain, &snao_end); + if (snao_end > short_no_arg_opts) + { + *snao_end++ = 0; + __argp_fmtstream_printf (stream, " [-%s]", short_no_arg_opts); + } + + /* Now a list of short options *with* arguments. */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_short_iterate (entry, usage_argful_short_opt, + entry->argp->argp_domain, stream); + + /* Finally, a list of long options (whew!). */ + for (entry = hol->entries, nentries = hol->num_entries + ; nentries > 0 + ; entry++, nentries--) + hol_entry_long_iterate (entry, usage_long_opt, + entry->argp->argp_domain, stream); + } +} + +/* Make a HOL containing all levels of options in ARGP. CLUSTER is the + cluster in which ARGP's entries should be clustered, or 0. */ +static struct hol * +argp_hol (const struct argp *argp, struct hol_cluster *cluster) +{ + const struct argp_child *child = argp->children; + struct hol *hol = make_hol (argp, cluster); + if (child) + while (child->argp) + { + struct hol_cluster *child_cluster = + ((child->group || child->header) + /* Put CHILD->argp within its own cluster. */ + ? hol_add_cluster (hol, child->group, child->header, + child - argp->children, cluster, argp) + /* Just merge it into the parent's cluster. */ + : cluster); + hol_append (hol, argp_hol (child->argp, child_cluster)) ; + child++; + } + return hol; +} + +/* Calculate how many different levels with alternative args strings exist in + ARGP. */ +static size_t +argp_args_levels (const struct argp *argp) +{ + size_t levels = 0; + const struct argp_child *child = argp->children; + + if (argp->args_doc && strchr (argp->args_doc, '\n')) + levels++; + + if (child) + while (child->argp) + levels += argp_args_levels ((child++)->argp); + + return levels; +} + +/* Print all the non-option args documented in ARGP to STREAM. Any output is + preceded by a space. LEVELS is a pointer to a byte vector the length + returned by argp_args_levels; it should be initialized to zero, and + updated by this routine for the next call if ADVANCE is true. True is + returned as long as there are more patterns to output. */ +static int +argp_args_usage (const struct argp *argp, const struct argp_state *state, + char **levels, int advance, argp_fmtstream_t stream) +{ + char *our_level = *levels; + int multiple = 0; + const struct argp_child *child = argp->children; + const char *tdoc = dgettext (argp->argp_domain, argp->args_doc), *nl = 0; + const char *fdoc = filter_doc (tdoc, ARGP_KEY_HELP_ARGS_DOC, argp, state); + + if (fdoc) + { + const char *cp = fdoc; + nl = strchr (cp, '\n'); + if (!nl) + { + nl = cp; + while (*nl != '\0') nl++; + } + + if (*nl != '\0') + /* This is a `multi-level' args doc; advance to the correct position + as determined by our state in LEVELS, and update LEVELS. */ + { + int i; + multiple = 1; + for (i = 0; i < *our_level; i++) + { + cp = nl + 1; + nl = strchr (cp, '\n'); + if (!nl) + { + nl = cp; + while (*nl != '\0') nl++; + } + } + (*levels)++; + } + + /* Manually do line wrapping so that it (probably) won't get wrapped at + any embedded spaces. */ + space (stream, 1 + nl - cp); + + __argp_fmtstream_write (stream, cp, nl - cp); + } + if (fdoc && fdoc != tdoc) + free ((char *)fdoc); /* Free user's modified doc string. */ + + if (child) + while (child->argp) + advance = !argp_args_usage ((child++)->argp, state, levels, advance, stream); + + if (advance && multiple) + { + /* Need to increment our level. */ + if (*nl) + /* There's more we can do here. */ + { + (*our_level)++; + advance = 0; /* Our parent shouldn't advance also. */ + } + else if (*our_level > 0) + /* We had multiple levels, but used them up; reset to zero. */ + *our_level = 0; + } + + return !advance; +} + +/* Print the documentation for ARGP to STREAM; if POST is false, then + everything preceeding a `\v' character in the documentation strings (or + the whole string, for those with none) is printed, otherwise, everything + following the `\v' character (nothing for strings without). Each separate + bit of documentation is separated a blank line, and if PRE_BLANK is true, + then the first is as well. If FIRST_ONLY is true, only the first + occurrence is output. Returns true if anything was output. */ +static int +argp_doc (const struct argp *argp, const struct argp_state *state, + int post, int pre_blank, int first_only, + argp_fmtstream_t stream) +{ + const char *text; + const char *inp_text; + char *tmp_text; + void *input = 0; + int anything = 0; + size_t inp_text_limit = 0; + const char *doc = dgettext (argp->argp_domain, argp->doc); + const struct argp_child *child = argp->children; + + if (doc) + { + char *vt = strchr (doc, '\v'); + inp_text = post ? (vt ? vt + 1 : 0) : doc; + inp_text_limit = (!post && vt) ? (vt - doc) : 0; + } + else + inp_text = 0; + + if (argp->help_filter) + /* We have to filter the doc strings. */ + { + if (inp_text_limit) + { + /* Copy INP_TEXT so that it's nul-terminated. */ + tmp_text = _malloc_r (_REENT, inp_text_limit); + strncpy (tmp_text, inp_text, inp_text_limit); + _free_r (_REENT, inp_text); + inp_text = tmp_text; + } + input = __argp_input (argp, state); + text = + (*argp->help_filter) (post + ? ARGP_KEY_HELP_POST_DOC + : ARGP_KEY_HELP_PRE_DOC, + inp_text, input); + } + else + text = (const char *) inp_text; + + if (text) + { + if (pre_blank) + __argp_fmtstream_putc (stream, '\n'); + + if (text == inp_text && inp_text_limit) + __argp_fmtstream_write (stream, inp_text, inp_text_limit); + else + __argp_fmtstream_puts (stream, text); + + if (__argp_fmtstream_point (stream) > __argp_fmtstream_lmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + + anything = 1; + } + + if (text && text != inp_text) + free ((char *) text); /* Free TEXT returned from the help filter. */ + if (inp_text && inp_text_limit && argp->help_filter) + free ((char *) inp_text); /* We copied INP_TEXT, so free it now. */ + + if (post && argp->help_filter) + /* Now see if we have to output a ARGP_KEY_HELP_EXTRA text. */ + { + text = (*argp->help_filter) (ARGP_KEY_HELP_EXTRA, 0, input); + if (text) + { + if (anything || pre_blank) + __argp_fmtstream_putc (stream, '\n'); + __argp_fmtstream_puts (stream, text); + free ((char *) text); + if (__argp_fmtstream_point (stream) + > __argp_fmtstream_lmargin (stream)) + __argp_fmtstream_putc (stream, '\n'); + anything = 1; + } + } + + if (child) + while (child->argp && !(first_only && anything)) + anything |= + argp_doc ((child++)->argp, state, + post, anything || pre_blank, first_only, + stream); + + return anything; +} + +/* Output a usage message for ARGP to STREAM. If called from + argp_state_help, STATE is the relevent parsing state. FLAGS are from the + set ARGP_HELP_*. NAME is what to use wherever a `program name' is + needed. */ +static void +_help (const struct argp *argp, const struct argp_state *state, FILE *stream, + unsigned flags, char *name) +{ + int anything = 0; /* Whether we've output anything. */ + struct hol *hol = 0; + argp_fmtstream_t fs; + + if (! stream) + return; + + _flockfile (stream); + + if (! uparams.valid) + fill_in_uparams (state); + + fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0); + if (! fs) + { + _funlockfile (stream); + return; + } + + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG)) + { + hol = argp_hol (argp, 0); + + /* If present, these options always come last. */ + hol_set_group (hol, "help", -1); + hol_set_group (hol, "version", -1); + + hol_sort (hol); + } + + if (flags & (ARGP_HELP_USAGE | ARGP_HELP_SHORT_USAGE)) + /* Print a short `Usage:' message. */ + { + int first_pattern = 1, more_patterns; + size_t num_pattern_levels = argp_args_levels (argp); + char *pattern_levels = alloca (num_pattern_levels); + + memset (pattern_levels, 0, num_pattern_levels); + + do + { + int old_lm; + int old_wm = __argp_fmtstream_set_wmargin (fs, uparams.usage_indent); + char *levels = pattern_levels; + + if (first_pattern) + __argp_fmtstream_printf (fs, "%s %s", + dgettext (argp->argp_domain, "Usage:"), + name); + else + __argp_fmtstream_printf (fs, "%s %s", + dgettext (argp->argp_domain, " or: "), + name); + + /* We set the lmargin as well as the wmargin, because hol_usage + manually wraps options with newline to avoid annoying breaks. */ + old_lm = __argp_fmtstream_set_lmargin (fs, uparams.usage_indent); + + if (flags & ARGP_HELP_SHORT_USAGE) + /* Just show where the options go. */ + { + if (hol->num_entries > 0) + __argp_fmtstream_puts (fs, dgettext (argp->argp_domain, + " [OPTION...]")); + } + else + /* Actually print the options. */ + { + hol_usage (hol, fs); + flags |= ARGP_HELP_SHORT_USAGE; /* But only do so once. */ + } + + more_patterns = argp_args_usage (argp, state, &levels, 1, fs); + + __argp_fmtstream_set_wmargin (fs, old_wm); + __argp_fmtstream_set_lmargin (fs, old_lm); + + __argp_fmtstream_putc (fs, '\n'); + anything = 1; + + first_pattern = 0; + } + while (more_patterns); + } + + if (flags & ARGP_HELP_PRE_DOC) + anything |= argp_doc (argp, state, 0, 0, 1, fs); + + if (flags & ARGP_HELP_SEE) + { + __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, "\ + Try `%s --help' or `%s --usage' for more information.\n"), + name, name); + anything = 1; + } + + if (flags & ARGP_HELP_LONG) + /* Print a long, detailed help message. */ + { + /* Print info about all the options. */ + if (hol->num_entries > 0) + { + if (anything) + __argp_fmtstream_putc (fs, '\n'); + hol_help (hol, state, fs); + anything = 1; + } + } + + if (flags & ARGP_HELP_POST_DOC) + /* Print any documentation strings at the end. */ + anything |= argp_doc (argp, state, 1, anything, 0, fs); + + if ((flags & ARGP_HELP_BUG_ADDR) && argp_program_bug_address) + { + if (anything) + __argp_fmtstream_putc (fs, '\n'); + __argp_fmtstream_printf (fs, dgettext (argp->argp_domain, + "Report bugs to %s.\n"), + argp_program_bug_address); + anything = 1; + } + + _funlockfile (stream); + + if (hol) + hol_free (hol); + + __argp_fmtstream_free (fs); +} + +/* Output a usage message for ARGP to STREAM. FLAGS are from the set + ARGP_HELP_*. NAME is what to use wherever a `program name' is needed. */ +void __argp_help (const struct argp *argp, FILE *stream, + unsigned flags, char *name) +{ + _help (argp, 0, stream, flags, name); +} +#ifdef weak_alias +weak_alias (__argp_help, argp_help) +#endif + +/* Output, if appropriate, a usage message for STATE to STREAM. FLAGS are + from the set ARGP_HELP_*. */ +void +__argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags) +{ + if ((!state || ! (state->flags & ARGP_NO_ERRS)) && stream) + { + if (state && (state->flags & ARGP_LONG_ONLY)) + flags |= ARGP_HELP_LONG_ONLY; + + _help (state ? state->root_argp : 0, state, stream, flags, + state ? state->name : program_invocation_short_name); + + if (!state || ! (state->flags & ARGP_NO_EXIT)) + { + if (flags & ARGP_HELP_EXIT_ERR) + exit (argp_err_exit_status); + if (flags & ARGP_HELP_EXIT_OK) + exit (0); + } + } +} +#ifdef weak_alias +weak_alias (__argp_state_help, argp_state_help) +#endif + +/* If appropriate, print the printf string FMT and following args, preceded + by the program name and `:', to stderr, and followed by a `Try ... --help' + message, then exit (1). */ +void +__argp_error (const struct argp_state *state, const char *fmt, ...) +{ + if (!state || !(state->flags & ARGP_NO_ERRS)) + { + FILE *stream = state ? state->err_stream : stderr; + + if (stream) + { + va_list ap; + + _flockfile (stream); + + va_start (ap, fmt); + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + { + char *buf; + + __asprintf (&buf, fmt, ap); + + __fwprintf (stream, L"%s: %s\n", + state ? state->name : program_invocation_short_name, + buf); + + free (buf); + } + else +#endif + { + fputs (state + ? state->name : program_invocation_short_name, + stream); + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + + vfprintf (stream, fmt, ap); + + putc_unlocked ('\n', stream); + } + + __argp_state_help (state, stream, ARGP_HELP_STD_ERR); + + va_end (ap); + + _funlockfile (stream); + } + } +} +#ifdef weak_alias +weak_alias (__argp_error, argp_error) +#endif + +/* Similar to the standard gnu error-reporting function error(), but will + respect the ARGP_NO_EXIT and ARGP_NO_ERRS flags in STATE, and will print + to STATE->err_stream. This is useful for argument parsing code that is + shared between program startup (when exiting is desired) and runtime + option parsing (when typically an error code is returned instead). The + difference between this function and argp_error is that the latter is for + *parsing errors*, and the former is for other problems that occur during + parsing but don't reflect a (syntactic) problem with the input. */ +void +__argp_failure (const struct argp_state *state, int status, int errnum, + const char *fmt, ...) +{ + if (!state || !(state->flags & ARGP_NO_ERRS)) + { + FILE *stream = state ? state->err_stream : stderr; + + if (stream) + { + _flockfile (stream); + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + __fwprintf (stream, L"%s", + state ? state->name : program_invocation_short_name); + else +#endif + fputs (state + ? state->name : program_invocation_short_name, + stream); + + if (fmt) + { + va_list ap; + + va_start (ap, fmt); +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + { + char *buf; + + __asprintf (&buf, fmt, ap); + + __fwprintf (stream, L": %s", buf); + + free (buf); + } + else +#endif + { + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + + vfprintf (stream, fmt, ap); + } + + va_end (ap); + } + + if (errnum) + { + char buf[200]; + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + __fwprintf (stream, L": %s", + strerror_r (errnum, buf, sizeof (buf))); + else +#endif + { + putc_unlocked (':', stream); + putc_unlocked (' ', stream); + fputs (strerror_r (errnum, buf, sizeof (buf)), stream); + } + } + +#ifdef USE_IN_LIBIO + if (_IO_fwide (stream, 0) > 0) + putwc_unlocked (L'\n', stream); + else +#endif + putc_unlocked ('\n', stream); + + _funlockfile (stream); + + if (status && (!state || !(state->flags & ARGP_NO_EXIT))) + exit (status); + } + } +} +#ifdef weak_alias +weak_alias (__argp_failure, argp_failure) +#endif diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-parse.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-parse.c new file mode 100644 index 000000000..afa6a3745 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-parse.c @@ -0,0 +1,1026 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Hierarchial argument parsing, layered over getopt + Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# if defined HAVE_LIBINTL_H || defined _LIBC +# include +# ifdef _LIBC +# undef dgettext +# define dgettext(domain, msgid) __dcgettext (domain, msgid, LC_MESSAGES) +# endif +# else +# define dgettext(domain, msgid) (msgid) +# define gettext(msgid) (msgid) +# endif +#endif +#ifndef N_ +# define N_(msgid) (msgid) +#endif + +#if _LIBC - 0 +#include +#else +#ifdef HAVE_CTHREADS_H +#include +#endif +#endif /* _LIBC */ + +#include +#include + +/* Getopt return values. */ +#define KEY_END (-1) /* The end of the options. */ +#define KEY_ARG 1 /* A non-option argument. */ +#define KEY_ERR '?' /* An error parsing the options. */ + +/* The meta-argument used to prevent any further arguments being interpreted + as options. */ +#define QUOTE "--" + +/* The number of bits we steal in a long-option value for our own use. */ +#define GROUP_BITS CHAR_BIT + +/* The number of bits available for the user value. */ +#define USER_BITS ((sizeof ((struct option *)0)->val * CHAR_BIT) - GROUP_BITS) +#define USER_MASK ((1 << USER_BITS) - 1) + +/* EZ alias for ARGP_ERR_UNKNOWN. */ +#define EBADKEY ARGP_ERR_UNKNOWN + +/* Default options. */ + +/* When argp is given the --HANG switch, _ARGP_HANG is set and argp will sleep + for one second intervals, decrementing _ARGP_HANG until it's zero. Thus + you can force the program to continue by attaching a debugger and setting + it to 0 yourself. */ +volatile int _argp_hang; + +#define OPT_PROGNAME -2 +#define OPT_USAGE -3 +#define OPT_HANG -4 + +static const struct argp_option argp_default_options[] = +{ + {"help", '?', 0, 0, N_("Give this help list"), -1}, + {"usage", OPT_USAGE, 0, 0, N_("Give a short usage message")}, + {"program-name",OPT_PROGNAME,"NAME", OPTION_HIDDEN, N_("Set the program name")}, + {"HANG", OPT_HANG, "SECS", OPTION_ARG_OPTIONAL | OPTION_HIDDEN, + N_("Hang for SECS seconds (default 3600)")}, + {0, 0} +}; + +static error_t +argp_default_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case '?': + __argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); + break; + case OPT_USAGE: + __argp_state_help (state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + break; + + case OPT_PROGNAME: /* Set the program name. */ + program_invocation_name = arg; + + /* [Note that some systems only have PROGRAM_INVOCATION_SHORT_NAME (aka + __PROGNAME), in which case, PROGRAM_INVOCATION_NAME is just defined + to be that, so we have to be a bit careful here.] */ + arg = strrchr (arg, '/'); + if (arg) + program_invocation_short_name = arg + 1; + else + program_invocation_short_name = program_invocation_name; + + /* Update what we use for messages. */ + state->name = program_invocation_short_name; + + if ((state->flags & (ARGP_PARSE_ARGV0 | ARGP_NO_ERRS)) + == ARGP_PARSE_ARGV0) + /* Update what getopt uses too. */ + state->argv[0] = program_invocation_name; + + break; + + case OPT_HANG: + _argp_hang = atoi (arg ? arg : "3600"); + while (_argp_hang-- > 0) + // Sripathi: + // Use a for loop to hang the execution rather than sleep + // since it is not implemented + // This will consume power but we don't really care since we will + // run a full-featured linux in real use cases and this will not be a problem + // Also, this a single-thread execution and there is nothing to context switch to + // while sleeping, so it shouldn't matter anyways. + // Choosing an arbitrary number to sleep. This necessarily may not map to 1 second + for (int i = 0; i < 1000; i++) + for (int j = 0; j <= (1 << 31); j++) + // Use this to prevent the compiler from optimizing this piece of code out. + __asm__ __volatile__("" : "+g" (i), "+g" (j) : :); + break; + + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_default_argp = + {argp_default_options, &argp_default_parser, NULL, NULL, NULL, NULL, "libc"}; + + +static const struct argp_option argp_version_options[] = +{ + {"version", 'V', 0, 0, N_("Print program version"), -1}, + {0, 0} +}; + +static error_t +argp_version_parser (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'V': + if (argp_program_version_hook) + (*argp_program_version_hook) (state->out_stream, state); + else if (argp_program_version) + fprintf (state->out_stream, "%s\n", argp_program_version); + else + __argp_error (state, dgettext (state->root_argp->argp_domain, + "(PROGRAM ERROR) No version known!?")); + if (! (state->flags & ARGP_NO_EXIT)) + exit (0); + break; + default: + return EBADKEY; + } + return 0; +} + +static const struct argp argp_version_argp = + {argp_version_options, &argp_version_parser, NULL, NULL, NULL, NULL, "libc"}; + +/* Returns the offset into the getopt long options array LONG_OPTIONS of a + long option with called NAME, or -1 if none is found. Passing NULL as + NAME will return the number of options. */ +static int +find_long_option (struct option *long_options, const char *name) +{ + struct option *l = long_options; + while (l->name != NULL) + if (name != NULL && strcmp (l->name, name) == 0) + return l - long_options; + else + l++; + if (name == NULL) + return l - long_options; + else + return -1; +} + +/* If we can, we regulate access to getopt, which is non-reentrant, with a + mutex. Since the case we're trying to guard against is two different + threads interfering, and it's possible that someone might want to call + argp_parse recursively (they're careful), we use a recursive lock if + possible. */ + +#if _LIBC - 0 + +__libc_lock_define_initialized_recursive (static, getopt_lock) +#define LOCK_GETOPT __libc_lock_lock_recursive (getopt_lock) +#define UNLOCK_GETOPT __libc_lock_unlock_recursive (getopt_lock) + +#else /* !_LIBC */ +#ifdef HAVE_CTHREADS_H + +static struct mutex getopt_lock = MUTEX_INITIALIZER; +#define LOCK_GETOPT mutex_lock (&getopt_lock) +#define UNLOCK_GETOPT mutex_unlock (&getopt_lock) + +#else /* !HAVE_CTHREADS_H */ + +#define LOCK_GETOPT (void)0 +#define UNLOCK_GETOPT (void)0 + +#endif /* HAVE_CTHREADS_H */ +#endif /* _LIBC */ + +/* This hack to allow programs that know what's going on to call argp + recursively. If someday argp is changed not to use the non-reentrant + getopt interface, we can get rid of this shit. XXX */ +void +_argp_unlock_xxx (void) +{ + UNLOCK_GETOPT; +} + +/* The state of a `group' during parsing. Each group corresponds to a + particular argp structure from the tree of such descending from the top + level argp passed to argp_parse. */ +struct group +{ + /* This group's parsing function. */ + argp_parser_t parser; + + /* Which argp this group is from. */ + const struct argp *argp; + + /* Points to the point in SHORT_OPTS corresponding to the end of the short + options for this group. We use it to determine from which group a + particular short options is from. */ + char *short_end; + + /* The number of non-option args sucessfully handled by this parser. */ + unsigned args_processed; + + /* This group's parser's parent's group. */ + struct group *parent; + unsigned parent_index; /* And the our position in the parent. */ + + /* These fields are swapped into and out of the state structure when + calling this group's parser. */ + void *input, **child_inputs; + void *hook; +}; + +/* Call GROUP's parser with KEY and ARG, swapping any group-specific info + from STATE before calling, and back into state afterwards. If GROUP has + no parser, EBADKEY is returned. */ +static error_t +group_parse (struct group *group, struct argp_state *state, int key, char *arg) +{ + if (group->parser) + { + error_t err; + state->hook = group->hook; + state->input = group->input; + state->child_inputs = group->child_inputs; + state->arg_num = group->args_processed; + err = (*group->parser)(key, arg, state); + group->hook = state->hook; + return err; + } + else + return EBADKEY; +} + +struct parser +{ + const struct argp *argp; + + /* SHORT_OPTS is the getopt short options string for the union of all the + groups of options. */ + char *short_opts; + /* LONG_OPTS is the array of getop long option structures for the union of + all the groups of options. */ + struct option *long_opts; + + /* States of the various parsing groups. */ + struct group *groups; + /* The end of the GROUPS array. */ + struct group *egroup; + /* An vector containing storage for the CHILD_INPUTS field in all groups. */ + void **child_inputs; + + /* True if we think using getopt is still useful; if false, then + remaining arguments are just passed verbatim with ARGP_KEY_ARG. This is + cleared whenever getopt returns KEY_END, but may be set again if the user + moves the next argument pointer backwards. */ + int try_getopt; + + /* State block supplied to parsing routines. */ + struct argp_state state; + + /* Memory used by this parser. */ + void *storage; +}; + +/* The next usable entries in the various parser tables being filled in by + convert_options. */ +struct parser_convert_state +{ + struct parser *parser; + char *short_end; + struct option *long_end; + void **child_inputs_end; +}; + +/* Converts all options in ARGP (which is put in GROUP) and ancestors + into getopt options stored in SHORT_OPTS and LONG_OPTS; SHORT_END and + CVT->LONG_END are the points at which new options are added. Returns the + next unused group entry. CVT holds state used during the conversion. */ +static struct group * +convert_options (const struct argp *argp, + struct group *parent, unsigned parent_index, + struct group *group, struct parser_convert_state *cvt) +{ + /* REAL is the most recent non-alias value of OPT. */ + const struct argp_option *real = argp->options; + const struct argp_child *children = argp->children; + + if (real || argp->parser) + { + const struct argp_option *opt; + + if (real) + for (opt = real; !__option_is_end (opt); opt++) + { + if (! (opt->flags & OPTION_ALIAS)) + /* OPT isn't an alias, so we can use values from it. */ + real = opt; + + if (! (real->flags & OPTION_DOC)) + /* A real option (not just documentation). */ + { + if (__option_is_short (opt)) + /* OPT can be used as a short option. */ + { + *cvt->short_end++ = opt->key; + if (real->arg) + { + *cvt->short_end++ = ':'; + if (real->flags & OPTION_ARG_OPTIONAL) + *cvt->short_end++ = ':'; + } + *cvt->short_end = '\0'; /* keep 0 terminated */ + } + + if (opt->name + && find_long_option (cvt->parser->long_opts, opt->name) < 0) + /* OPT can be used as a long option. */ + { + cvt->long_end->name = opt->name; + cvt->long_end->has_arg = + (real->arg + ? (real->flags & OPTION_ARG_OPTIONAL + ? optional_argument + : required_argument) + : no_argument); + cvt->long_end->flag = 0; + /* we add a disambiguating code to all the user's + values (which is removed before we actually call + the function to parse the value); this means that + the user loses use of the high 8 bits in all his + values (the sign of the lower bits is preserved + however)... */ + cvt->long_end->val = + ((opt->key | real->key) & USER_MASK) + + (((group - cvt->parser->groups) + 1) << USER_BITS); + + /* Keep the LONG_OPTS list terminated. */ + (++cvt->long_end)->name = NULL; + } + } + } + + group->parser = argp->parser; + group->argp = argp; + group->short_end = cvt->short_end; + group->args_processed = 0; + group->parent = parent; + group->parent_index = parent_index; + group->input = 0; + group->hook = 0; + group->child_inputs = 0; + + if (children) + /* Assign GROUP's CHILD_INPUTS field some space from + CVT->child_inputs_end.*/ + { + unsigned num_children = 0; + while (children[num_children].argp) + num_children++; + group->child_inputs = cvt->child_inputs_end; + cvt->child_inputs_end += num_children; + } + + parent = group++; + } + else + parent = 0; + + if (children) + { + unsigned index = 0; + while (children->argp) + group = + convert_options (children++->argp, parent, index++, group, cvt); + } + + return group; +} + +/* Find the merged set of getopt options, with keys appropiately prefixed. */ +static void +parser_convert (struct parser *parser, const struct argp *argp, int flags) +{ + struct parser_convert_state cvt; + + cvt.parser = parser; + cvt.short_end = parser->short_opts; + cvt.long_end = parser->long_opts; + cvt.child_inputs_end = parser->child_inputs; + + if (flags & ARGP_IN_ORDER) + *cvt.short_end++ = '-'; + else if (flags & ARGP_NO_ARGS) + *cvt.short_end++ = '+'; + *cvt.short_end = '\0'; + + cvt.long_end->name = NULL; + + parser->argp = argp; + + if (argp) + parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt); + else + parser->egroup = parser->groups; /* No parsers at all! */ +} + +/* Lengths of various parser fields which we will allocated. */ +struct parser_sizes +{ + size_t short_len; /* Getopt short options string. */ + size_t long_len; /* Getopt long options vector. */ + size_t num_groups; /* Group structures we allocate. */ + size_t num_child_inputs; /* Child input slots. */ +}; + +/* For ARGP, increments the NUM_GROUPS field in SZS by the total number of + argp structures descended from it, and the SHORT_LEN & LONG_LEN fields by + the maximum lengths of the resulting merged getopt short options string and + long-options array, respectively. */ +static void +calc_sizes (const struct argp *argp, struct parser_sizes *szs) +{ + const struct argp_child *child = argp->children; + const struct argp_option *opt = argp->options; + + if (opt || argp->parser) + { + szs->num_groups++; + if (opt) + { + int num_opts = 0; + while (!__option_is_end (opt++)) + num_opts++; + szs->short_len += num_opts * 3; /* opt + up to 2 `:'s */ + szs->long_len += num_opts; + } + } + + if (child) + while (child->argp) + { + calc_sizes ((child++)->argp, szs); + szs->num_child_inputs++; + } +} + +/* Initializes PARSER to parse ARGP in a manner described by FLAGS. */ +static error_t +parser_init (struct parser *parser, const struct argp *argp, + int argc, char **argv, int flags, void *input) +{ + error_t err = 0; + struct group *group; + struct parser_sizes szs; + + szs.short_len = (flags & ARGP_NO_ARGS) ? 0 : 1; + szs.long_len = 0; + szs.num_groups = 0; + szs.num_child_inputs = 0; + + if (argp) + calc_sizes (argp, &szs); + + /* Lengths of the various bits of storage used by PARSER. */ +#define GLEN (szs.num_groups + 1) * sizeof (struct group) +#define CLEN (szs.num_child_inputs * sizeof (void *)) +#define LLEN ((szs.long_len + 1) * sizeof (struct option)) +#define SLEN (szs.short_len + 1) + + parser->storage = malloc (GLEN + CLEN + LLEN + SLEN); + if (! parser->storage) + return ENOMEM; + + parser->groups = parser->storage; + parser->child_inputs = parser->storage + GLEN; + parser->long_opts = parser->storage + GLEN + CLEN; + parser->short_opts = parser->storage + GLEN + CLEN + LLEN; + + memset (parser->child_inputs, 0, szs.num_child_inputs * sizeof (void *)); + parser_convert (parser, argp, flags); + + memset (&parser->state, 0, sizeof (struct argp_state)); + parser->state.root_argp = parser->argp; + parser->state.argc = argc; + parser->state.argv = argv; + parser->state.flags = flags; + parser->state.err_stream = stderr; + parser->state.out_stream = stdout; + parser->state.next = 0; /* Tell getopt to initialize. */ + parser->state.pstate = parser; + + parser->try_getopt = 1; + + /* Call each parser for the first time, giving it a chance to propagate + values to child parsers. */ + if (parser->groups < parser->egroup) + parser->groups->input = input; + for (group = parser->groups; + group < parser->egroup && (!err || err == EBADKEY); + group++) + { + if (group->parent) + /* If a child parser, get the initial input value from the parent. */ + group->input = group->parent->child_inputs[group->parent_index]; + + if (!group->parser + && group->argp->children && group->argp->children->argp) + /* For the special case where no parsing function is supplied for an + argp, propagate its input to its first child, if any (this just + makes very simple wrapper argps more convenient). */ + group->child_inputs[0] = group->input; + + err = group_parse (group, &parser->state, ARGP_KEY_INIT, 0); + } + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + if (err) + return err; + + /* Getopt is (currently) non-reentrant. */ + LOCK_GETOPT; + + if (parser->state.flags & ARGP_NO_ERRS) + { + opterr = 0; + if (parser->state.flags & ARGP_PARSE_ARGV0) + /* getopt always skips ARGV[0], so we have to fake it out. As long + as OPTERR is 0, then it shouldn't actually try to access it. */ + parser->state.argv--, parser->state.argc++; + } + else + opterr = 1; /* Print error messages. */ + + if (parser->state.argv == argv && argv[0]) + /* There's an argv[0]; use it for messages. */ + { + char *short_name = strrchr (argv[0], '/'); + parser->state.name = short_name ? short_name + 1 : argv[0]; + } + else + parser->state.name = program_invocation_short_name; + + return 0; +} + +/* Free any storage consumed by PARSER (but not PARSER itself). */ +static error_t +parser_finalize (struct parser *parser, + error_t err, int arg_ebadkey, int *end_index) +{ + struct group *group; + + UNLOCK_GETOPT; + + if (err == EBADKEY && arg_ebadkey) + /* Suppress errors generated by unparsed arguments. */ + err = 0; + + if (! err) + { + if (parser->state.next == parser->state.argc) + /* We successfully parsed all arguments! Call all the parsers again, + just a few more times... */ + { + for (group = parser->groups; + group < parser->egroup && (!err || err==EBADKEY); + group++) + if (group->args_processed == 0) + err = group_parse (group, &parser->state, ARGP_KEY_NO_ARGS, 0); + for (group = parser->egroup - 1; + group >= parser->groups && (!err || err==EBADKEY); + group--) + err = group_parse (group, &parser->state, ARGP_KEY_END, 0); + + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + + /* Tell the user that all arguments are parsed. */ + if (end_index) + *end_index = parser->state.next; + } + else if (end_index) + /* Return any remaining arguments to the user. */ + *end_index = parser->state.next; + else + /* No way to return the remaining arguments, they must be bogus. */ + { + if (!(parser->state.flags & ARGP_NO_ERRS) + && parser->state.err_stream) + fprintf (parser->state.err_stream, + dgettext (parser->argp->argp_domain, + "%s: Too many arguments\n"), + parser->state.name); + err = EBADKEY; + } + } + + /* Okay, we're all done, with either an error or success; call the parsers + to indicate which one. */ + + if (err) + { + /* Maybe print an error message. */ + if (err == EBADKEY) + /* An appropriate message describing what the error was should have + been printed earlier. */ + __argp_state_help (&parser->state, parser->state.err_stream, + ARGP_HELP_STD_ERR); + + /* Since we didn't exit, give each parser an error indication. */ + for (group = parser->groups; group < parser->egroup; group++) + group_parse (group, &parser->state, ARGP_KEY_ERROR, 0); + } + else + /* Notify parsers of success, and propagate back values from parsers. */ + { + /* We pass over the groups in reverse order so that child groups are + given a chance to do there processing before passing back a value to + the parent. */ + for (group = parser->egroup - 1 + ; group >= parser->groups && (!err || err == EBADKEY) + ; group--) + err = group_parse (group, &parser->state, ARGP_KEY_SUCCESS, 0); + if (err == EBADKEY) + err = 0; /* Some parser didn't understand. */ + } + + /* Call parsers once more, to do any final cleanup. Errors are ignored. */ + for (group = parser->egroup - 1; group >= parser->groups; group--) + group_parse (group, &parser->state, ARGP_KEY_FINI, 0); + + if (err == EBADKEY) + err = EINVAL; + + free (parser->storage); + + return err; +} + +/* Call the user parsers to parse the non-option argument VAL, at the current + position, returning any error. The state NEXT pointer is assumed to have + been adjusted (by getopt) to point after this argument; this function will + adjust it correctly to reflect however many args actually end up being + consumed. */ +static error_t +parser_parse_arg (struct parser *parser, char *val) +{ + /* Save the starting value of NEXT, first adjusting it so that the arg + we're parsing is again the front of the arg vector. */ + int index = --parser->state.next; + error_t err = EBADKEY; + struct group *group; + int key = 0; /* Which of ARGP_KEY_ARG[S] we used. */ + + /* Try to parse the argument in each parser. */ + for (group = parser->groups + ; group < parser->egroup && err == EBADKEY + ; group++) + { + parser->state.next++; /* For ARGP_KEY_ARG, consume the arg. */ + key = ARGP_KEY_ARG; + err = group_parse (group, &parser->state, key, val); + + if (err == EBADKEY) + /* This parser doesn't like ARGP_KEY_ARG; try ARGP_KEY_ARGS instead. */ + { + parser->state.next--; /* For ARGP_KEY_ARGS, put back the arg. */ + key = ARGP_KEY_ARGS; + err = group_parse (group, &parser->state, key, 0); + } + } + + if (! err) + { + if (key == ARGP_KEY_ARGS) + /* The default for ARGP_KEY_ARGS is to assume that if NEXT isn't + changed by the user, *all* arguments should be considered + consumed. */ + parser->state.next = parser->state.argc; + + if (parser->state.next > index) + /* Remember that we successfully processed a non-option + argument -- but only if the user hasn't gotten tricky and set + the clock back. */ + (--group)->args_processed += (parser->state.next - index); + else + /* The user wants to reparse some args, give getopt another try. */ + parser->try_getopt = 1; + } + + return err; +} + +/* Call the user parsers to parse the option OPT, with argument VAL, at the + current position, returning any error. */ +static error_t +parser_parse_opt (struct parser *parser, int opt, char *val) +{ + /* The group key encoded in the high bits; 0 for short opts or + group_number + 1 for long opts. */ + int group_key = opt >> USER_BITS; + error_t err = EBADKEY; + + if (group_key == 0) + /* A short option. By comparing OPT's position in SHORT_OPTS to the + various starting positions in each group's SHORT_END field, we can + determine which group OPT came from. */ + { + struct group *group; + char *short_index = strchr (parser->short_opts, opt); + + if (short_index) + for (group = parser->groups; group < parser->egroup; group++) + if (group->short_end > short_index) + { + err = group_parse (group, &parser->state, opt, optarg); + break; + } + } + else + /* A long option. We use shifts instead of masking for extracting + the user value in order to preserve the sign. */ + err = + group_parse (&parser->groups[group_key - 1], &parser->state, + (opt << GROUP_BITS) >> GROUP_BITS, optarg); + + if (err == EBADKEY) + /* At least currently, an option not recognized is an error in the + parser, because we pre-compute which parser is supposed to deal + with each option. */ + { + static const char bad_key_err[] = + N_("(PROGRAM ERROR) Option should have been recognized!?"); + if (group_key == 0) + __argp_error (&parser->state, "-%c: %s", opt, + dgettext (parser->argp->argp_domain, bad_key_err)); + else + { + struct option *long_opt = parser->long_opts; + while (long_opt->val != opt && long_opt->name) + long_opt++; + __argp_error (&parser->state, "--%s: %s", + long_opt->name ? long_opt->name : "???", + dgettext (parser->argp->argp_domain, bad_key_err)); + } + } + + return err; +} + +/* Parse the next argument in PARSER (as indicated by PARSER->state.next). + Any error from the parsers is returned, and *ARGP_EBADKEY indicates + whether a value of EBADKEY is due to an unrecognized argument (which is + generally not fatal). */ +static error_t +parser_parse_next (struct parser *parser, int *arg_ebadkey) +{ + int opt; + error_t err = 0; + + if (parser->state.quoted && parser->state.next < parser->state.quoted) + /* The next argument pointer has been moved to before the quoted + region, so pretend we never saw the quoting `--', and give getopt + another chance. If the user hasn't removed it, getopt will just + process it again. */ + parser->state.quoted = 0; + + if (parser->try_getopt && !parser->state.quoted) + /* Give getopt a chance to parse this. */ + { + optind = parser->state.next; /* Put it back in OPTIND for getopt. */ + optopt = KEY_END; /* Distinguish KEY_ERR from a real option. */ + if (parser->state.flags & ARGP_LONG_ONLY) + opt = getopt_long_only (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0); + else + opt = getopt_long (parser->state.argc, parser->state.argv, + parser->short_opts, parser->long_opts, 0); + parser->state.next = optind; /* And see what getopt did. */ + + if (opt == KEY_END) + /* Getopt says there are no more options, so stop using + getopt; we'll continue if necessary on our own. */ + { + parser->try_getopt = 0; + if (parser->state.next > 1 + && strcmp (parser->state.argv[parser->state.next - 1], QUOTE) + == 0) + /* Not only is this the end of the options, but it's a + `quoted' region, which may have args that *look* like + options, so we definitely shouldn't try to use getopt past + here, whatever happens. */ + parser->state.quoted = parser->state.next; + } + else if (opt == KEY_ERR && optopt != KEY_END) + /* KEY_ERR can have the same value as a valid user short + option, but in the case of a real error, getopt sets OPTOPT + to the offending character, which can never be KEY_END. */ + { + *arg_ebadkey = 0; + return EBADKEY; + } + } + else + opt = KEY_END; + + if (opt == KEY_END) + { + /* We're past what getopt considers the options. */ + if (parser->state.next >= parser->state.argc + || (parser->state.flags & ARGP_NO_ARGS)) + /* Indicate that we're done. */ + { + *arg_ebadkey = 1; + return EBADKEY; + } + else + /* A non-option arg; simulate what getopt might have done. */ + { + opt = KEY_ARG; + optarg = parser->state.argv[parser->state.next++]; + } + } + + if (opt == KEY_ARG) + /* A non-option argument; try each parser in turn. */ + err = parser_parse_arg (parser, optarg); + else + err = parser_parse_opt (parser, opt, optarg); + + if (err == EBADKEY) + *arg_ebadkey = (opt == KEY_END || opt == KEY_ARG); + + return err; +} + +/* Parse the options strings in ARGC & ARGV according to the argp in ARGP. + FLAGS is one of the ARGP_ flags above. If END_INDEX is non-NULL, the + index in ARGV of the first unparsed option is returned in it. If an + unknown option is present, EINVAL is returned; if some parser routine + returned a non-zero value, it is returned; otherwise 0 is returned. */ +error_t +__argp_parse (const struct argp *argp, int argc, char **argv, unsigned flags, + int *end_index, void *input) +{ + error_t err; + struct parser parser; + + /* If true, then err == EBADKEY is a result of a non-option argument failing + to be parsed (which in some cases isn't actually an error). */ + int arg_ebadkey = 0; + + // Sripathi: + // Forward declare the struct pointers since malloc is being used instead of alloca + struct argp_child *child; + struct argp *top_argp; + + // Set these to NULL when not used + child = NULL; + top_argp = NULL; + + if (! (flags & ARGP_NO_HELP)) + /* Add our own options. */ + { + // Sripathi: + // Originally alloca was used but since newlib does not implement that + // we are switching over to malloc which is a lot slower + child = (struct argp_child *) malloc (4 * sizeof (struct argp_child)); + top_argp = (struct argp *) malloc (sizeof (struct argp)); + + /* TOP_ARGP has no options, it just serves to group the user & default + argps. */ + memset (top_argp, 0, sizeof (struct argp)); + top_argp->children = child; + + memset (child, 0, 4 * sizeof (struct argp_child)); + + if (argp) + (child++)->argp = argp; + (child++)->argp = &argp_default_argp; + if (argp_program_version || argp_program_version_hook) + (child++)->argp = &argp_version_argp; + child->argp = 0; + + argp = top_argp; + } + + /* Construct a parser for these arguments. */ + err = parser_init (&parser, argp, argc, argv, flags, input); + + if (! err) + /* Parse! */ + { + while (! err) + err = parser_parse_next (&parser, &arg_ebadkey); + err = parser_finalize (&parser, err, arg_ebadkey, end_index); + } + + // Sripathi: + // malloc was used to allocate space for the argp_child and argp structs + // alloca automatically freed the memory when the function returned + // but since we are using malloc, we need to explicitly free it to + // avoid memory leaks + free(top_argp->children); + free(top_argp); + + return err; +} +#ifdef weak_alias +weak_alias (__argp_parse, argp_parse) +#endif + +/* Return the input field for ARGP in the parser corresponding to STATE; used + by the help routines. */ +void * +__argp_input (const struct argp *argp, const struct argp_state *state) +{ + if (state) + { + struct group *group; + struct parser *parser = state->pstate; + + for (group = parser->groups; group < parser->egroup; group++) + if (group->argp == argp) + return group->input; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__argp_input, _argp_input) +#endif diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-pv.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-pv.c new file mode 100644 index 000000000..5902498e1 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-pv.c @@ -0,0 +1,54 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Default definition for ARGP_PROGRAM_VERSION. + Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* If set by the user program to a non-zero value, then a default option + --version is added (unless the ARGP_NO_HELP flag is used), which will + print this this string followed by a newline and exit (unless the + ARGP_NO_EXIT flag is used). Overridden by ARGP_PROGRAM_VERSION_HOOK. */ +const char *argp_program_version; diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-pvh.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-pvh.c new file mode 100644 index 000000000..99d6522de --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-pvh.c @@ -0,0 +1,61 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Default definition for ARGP_PROGRAM_VERSION_HOOK. + Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +/* If set by the user program to a non-zero value, then a default option + --version is added (unless the ARGP_NO_HELP flag is used), which calls + this function with a stream to print the version to and a pointer to the + current parsing state, and then exits (unless the ARGP_NO_EXIT flag is + used). This variable takes precedent over ARGP_PROGRAM_VERSION. */ +void (*argp_program_version_hook) (FILE *stream, struct argp_state *state); diff --git a/libraries/platforms/hammerblade-vcs/src/argp/argp-xinl.c b/libraries/platforms/hammerblade-vcs/src/argp/argp-xinl.c new file mode 100644 index 000000000..61c5a8801 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/argp/argp-xinl.c @@ -0,0 +1,71 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is a slightly modified copy of the argp library from Newlib + +/* Real definitions for extern inline functions in argp.h + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#ifndef __USE_EXTERN_INLINES +# define __USE_EXTERN_INLINES 1 +#endif +#define ARGP_EI +#undef __OPTIMIZE__ +#define __OPTIMIZE__ 1 +#include + +/* Add weak aliases. */ +#if _LIBC - 0 && defined (weak_alias) + +weak_alias (__argp_usage, argp_usage) +weak_alias (__option_is_short, _option_is_short) +weak_alias (__option_is_end, _option_is_end) + +#endif diff --git a/libraries/platforms/hammerblade-vcs/src/bsg_newlib_intf.c b/libraries/platforms/hammerblade-vcs/src/bsg_newlib_intf.c new file mode 100644 index 000000000..715f061bc --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/bsg_newlib_intf.c @@ -0,0 +1,23 @@ + +#include + +#define HOST_DEV_BASE_ADDR 0x00100000 + +#define GETCHAR_BASE_ADDR ((char *)(HOST_DEV_BASE_ADDR | 0x00000)) +#define PUTCHAR_BASE_ADDR ((char *)(HOST_DEV_BASE_ADDR | 0x01000)) +#define FINISH_BASE_ADDR ((char *)(HOST_DEV_BASE_ADDR | 0x02000)) +#define PUTCH_CORE_BASE_ADDR ((char *)(HOST_DEV_BASE_ADDR | 0x03000)) +#define BOOTROM_BASE_ADDR ((char *)(HOST_DEV_BASE_ADDR | 0x10000)) + +void dramfs_exit(int exit_status) { + *(FINISH_BASE_ADDR) = exit_status; +} + +void dramfs_sendchar(char ch) { + *(PUTCHAR_BASE_ADDR) = ch; +} + +int dramfs_getchar(void) { + return *(GETCHAR_BASE_ADDR); +} + diff --git a/libraries/platforms/hammerblade-vcs/src/flockfile.c b/libraries/platforms/hammerblade-vcs/src/flockfile.c new file mode 100644 index 000000000..57110f6a4 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/flockfile.c @@ -0,0 +1,41 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// RISC-V Newlib does not seem to define this function anywhere although +// it is declared in stdio.h. +// Since there is no threading library, implement this function as a no-op + +#include + +/** + * Lock a file. This function is currently a no-op since CUDA-lite is not thread-safe. + * @param[in] fp A FILE object pointer + */ +void flockfile(FILE *fp) +{ + // Do nothing +} diff --git a/libraries/platforms/hammerblade-vcs/src/funlockfile.c b/libraries/platforms/hammerblade-vcs/src/funlockfile.c new file mode 100644 index 000000000..24d495e96 --- /dev/null +++ b/libraries/platforms/hammerblade-vcs/src/funlockfile.c @@ -0,0 +1,41 @@ +// Copyright (c) 2020, University of Washington All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list +// of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// +// Neither the name of the copyright holder nor the names of its contributors may +// be used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// RISC-V Newlib does not seem to define this function anywhere although +// it is declared in stdio.h. +// Since there is no threading library, implement this function as a no-op + +#include + +/** + * Unlock a file. This function is currently a no-op since CUDA-lite is not thread-safe. + * @param[in] fp A FILE object pointer + */ +void funlockfile(FILE *fp) +{ + // Do nothing +} diff --git a/libraries/platforms/zynqparrot-fpga/bsg_manycore_platform.cpp b/libraries/platforms/zynqparrot-fpga/bsg_manycore_platform.cpp new file mode 100644 index 000000000..5f469dfdf --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/bsg_manycore_platform.cpp @@ -0,0 +1,372 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +///////////////////////////////////////////// +// Header Definitions +///////////////////////////////////////////// + +#define _BSG_PRINTING_H +#include +#include + +#include +#include + +#include + +///////////////////////////////////////////// +// Globals +///////////////////////////////////////////// +bsg_zynq_pl *zpl; + +///////////////////////////////////////////// +// Convenience Functions +///////////////////////////////////////////// + +inline void send_mc_request_packet(bsg_zynq_pl *zpl, hb_mc_request_packet_t *packet) { + int axil_len = sizeof(hb_mc_request_packet_t) / 4; + + uint32_t *pkt_data = reinterpret_cast(packet); + for (int i = 0; i < axil_len; i++) { + while (!zpl->axil_read(GP0_RD_EP_REQ_FIFO_CTR)); + zpl->axil_write(GP0_WR_EP_REQ_FIFO_DATA, pkt_data[i], 0xf); + } +} + +inline void recv_mc_response_packet(bsg_zynq_pl *zpl, hb_mc_response_packet_t *packet) { + int axil_len = sizeof(hb_mc_response_packet_t) / 4; + + uint32_t *pkt_data = reinterpret_cast(packet); + for (int i = 0; i < axil_len; i++) { + while (!zpl->axil_read(GP0_RD_MC_RSP_FIFO_CTR)); + pkt_data[i] = zpl->axil_read(GP0_RD_MC_RSP_FIFO_DATA); + } +} + +inline void recv_mc_request_packet(bsg_zynq_pl *zpl, hb_mc_request_packet_t *packet) { + int axil_len = sizeof(hb_mc_request_packet_t) / 4; + + uint32_t *pkt_data = reinterpret_cast(packet); + for (int i = 0; i < axil_len; i++) { + while (!zpl->axil_read(GP0_RD_MC_REQ_FIFO_CTR)); + pkt_data[i] = zpl->axil_read(GP0_RD_MC_REQ_FIFO_DATA); + } +} + +inline void send_mc_write(bsg_zynq_pl *zpl, uint8_t x, uint8_t y, uint32_t epa, int32_t data) { + hb_mc_request_packet_t req_pkt; + + req_pkt.op_v2 = 2; // SW + req_pkt.reg_id = 0xff; // unused + req_pkt.payload = data; + req_pkt.x_src = BSG_MANYCORE_MACHINE_HOST_COORD_X; + req_pkt.y_src = BSG_MANYCORE_MACHINE_HOST_COORD_Y; + req_pkt.x_dst = x; + req_pkt.y_dst = y; + req_pkt.addr = epa >> 2; + + send_mc_request_packet(zpl, &req_pkt); +} + +inline int32_t send_mc_read(bsg_zynq_pl *zpl, uint8_t x, uint8_t y, uint32_t epa) { + hb_mc_request_packet_t req_pkt; + + req_pkt.op_v2 = 0; // LD + req_pkt.reg_id = 0xff; // unused + req_pkt.payload = 0; // Ignore payload + req_pkt.x_src = BSG_MANYCORE_MACHINE_HOST_COORD_X; + req_pkt.y_src = BSG_MANYCORE_MACHINE_HOST_COORD_Y; + req_pkt.x_dst = x; + req_pkt.y_dst = y; + req_pkt.addr = epa >> 2; + + send_mc_request_packet(zpl, &req_pkt); + + hb_mc_response_packet_t resp_pkt; + recv_mc_response_packet(zpl, &resp_pkt); + + return resp_pkt.data; +} + +///////////////////////////////////////////// +// Platform Functions +///////////////////////////////////////////// + +/** + * Transmit a request packet to manycore hardware + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] request A request packet to transmit to manycore hardware + * @param[in] timeout A timeout counter. Unused - set to -1 to wait forever. + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_transmit(hb_mc_manycore_t *mc, + hb_mc_packet_t *packet, + hb_mc_fifo_tx_t type, + long timeout) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + const char *typestr = hb_mc_fifo_tx_to_string(type); + + int err; + if (timeout != -1) { + bsg_pr_err("%s: Only a timeout value of -1 is supported\n", + __func__); + return HB_MC_INVALID; + } + + if (type == HB_MC_FIFO_TX_RSP) { + bsg_pr_err("TX Response Not Supported!\n", typestr); + return HB_MC_NOIMPL; + } + + send_mc_request_packet(zpl, (hb_mc_request_packet_t *)packet); + + return HB_MC_SUCCESS; +} + +/** + * Receive a packet from manycore hardware + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] response A packet into which data should be read + * @param[in] timeout A timeout counter. Unused - set to -1 to wait forever. + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_receive(hb_mc_manycore_t *mc, + hb_mc_packet_t *packet, + hb_mc_fifo_rx_t type, + long timeout) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + if (timeout != -1) { + bsg_pr_err("%s: Only a timeout value of -1 is supported\n", + __func__); + return HB_MC_INVALID; + } + + switch (type) { + case HB_MC_FIFO_RX_REQ: + recv_mc_request_packet(zpl, (hb_mc_request_packet_t *)packet); + break; + case HB_MC_FIFO_RX_RSP: + recv_mc_response_packet(zpl, (hb_mc_response_packet_t *)packet); + default: + bsg_pr_err("%s: Unknown packet type\n", __func__); + return HB_MC_NOIMPL; + } + + return HB_MC_SUCCESS; +} + +/** + * Read the configuration register at an index + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] idx Configuration register index to access + * @param[out] config Configuration value at index + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_get_config_at(hb_mc_manycore_t *mc, + unsigned int idx, + hb_mc_config_raw_t *config) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + if (idx < HB_MC_CONFIG_MAX) { + zpl->axil_write(GP0_WR_CSR_ROM_ADDR, idx, 0xf); + *config = zpl->axil_read(GP0_RD_ROM_DATA); + return HB_MC_SUCCESS; + } + + return HB_MC_INVALID; +} + +/** + * Clean up the runtime platform + * @param[in] mc A manycore to clean up + */ +void hb_mc_platform_cleanup(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + delete zpl; + + return; +} + +/** + * Initialize the runtime platform + * @param[in] mc A manycore to initialize + * @param[in] id ID which selects the physical hardware from which this manycore is configured + * @return HB_MC_FAIL if an error occured. HB_MC_SUCCESS otherwise. + */ +int hb_mc_platform_init(hb_mc_manycore_t *mc, + hb_mc_manycore_id_t id) +{ + int err; + zpl = new bsg_zynq_pl(0, NULL); + + if (mc->platform) + return HB_MC_INITIALIZED_TWICE; + + if (id != 0) { + return HB_MC_INVALID; + } + + mc->platform = reinterpret_cast(zpl); + + bsg_tag_bitbang *btb = new bsg_tag_bitbang(zpl, GP0_WR_CSR_TAG_BITBANG, TAG_NUM_CLIENTS, TAG_MAX_LEN); + bsg_tag_client *mc_reset_client = new bsg_tag_client(TAG_CLIENT_MC_RESET_ID, TAG_CLIENT_MC_RESET_WIDTH); + + // Reset the bsg tag master + btb->reset_master(); + // Reset bsg client0 + btb->reset_client(mc_reset_client); + // Set bsg client0 to 1 (assert BP reset) + btb->set_client(mc_reset_client, 0x1); + // Set bsg client0 to 0 (deassert BP reset) + btb->set_client(mc_reset_client, 0x0); + + // We need some additional toggles for data to propagate through + btb->idle(50); + // Deassert the active-low system reset as we finish initializing the whole system + zpl->axil_write(GP0_WR_CSR_SYS_RESETN, 0x1, 0xF); + + return HB_MC_SUCCESS; +} + + +/** + * Stall until the all requests (and responses) have reached their destination. + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] timeout A timeout counter. Unused - set to -1 to wait forever. + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_fence(hb_mc_manycore_t *mc, + long timeout) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + +/** + * Signal the hardware to start a bulk transfer over the network + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_start_bulk_transfer(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + +/** + * Signal the hardware to end a bulk transfer over the network + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_finish_bulk_transfer(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + +/** + * Get the current cycle counter of the Manycore Platform + * + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[out] time The current counter value. + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_get_cycle(hb_mc_manycore_t *mc, uint64_t *time) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Get the number of instructions executed for a certain class of instructions + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @param[in] itype An enum defining the class of instructions to query. + * @param[out] count The number of instructions executed in the queried class. + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_get_icount(hb_mc_manycore_t *mc, bsg_instr_type_e itype, int *count) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Enable trace file generation (vanilla_operation_trace.csv) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_trace_enable(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Disable trace file generation (vanilla_operation_trace.csv) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_trace_disable(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Enable log file generation (vanilla.log) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_log_enable(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Disable log file generation (vanilla.log) + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_log_disable(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_NOIMPL; +} + +/** + * Check if chip reset has completed. + * @param[in] mc A manycore instance initialized with hb_mc_manycore_init() + * @return HB_MC_SUCCESS on success. Otherwise an error code defined in bsg_manycore_errno.h. + */ +int hb_mc_platform_wait_reset_done(hb_mc_manycore_t *mc) +{ + bsg_zynq_pl *zpl = reinterpret_cast(mc->platform); + + return HB_MC_SUCCESS; +} + diff --git a/libraries/platforms/zynqparrot-fpga/bsg_manycore_regression_platform.h b/libraries/platforms/zynqparrot-fpga/bsg_manycore_regression_platform.h new file mode 100644 index 000000000..c53482254 --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/bsg_manycore_regression_platform.h @@ -0,0 +1,28 @@ +#pragma once +#ifdef __cplusplus +extern "C" { +#endif + +// To make your program HammerBlade cross-platform compatible, +// define a function with the signature of "main", and then +// use this macro to mark it as the entry point of your program +// +// Example: +// +// int MyMain(int argc, char *argv[]) { +// /* your code here */ +// } +// declare_program_main("The name of your test", MyMain) +// +#define declare_program_main(test_name, name) \ + int main(int argc, char *argv[]) { \ + bsg_pr_test_info("Regression Test: %s\n", test_name); \ + int rc = name(argc, argv); \ + bsg_pr_test_pass_fail(rc == HB_MC_SUCCESS); \ + return rc; \ + } + + +#ifdef __cplusplus +} +#endif diff --git a/libraries/platforms/zynqparrot-fpga/compilation.mk b/libraries/platforms/zynqparrot-fpga/compilation.mk new file mode 100644 index 000000000..ca8c90af1 --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/compilation.mk @@ -0,0 +1,62 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile fragment defines rules for compilation of the C/C++ +# files for running regression tests. + +ORANGE=\033[0;33m +RED=\033[0;31m +NC=\033[0m + +# This file REQUIRES several variables to be set. They are typically +# set by the Makefile that includes this makefile.. +# + +DEFINES += -DFPGA +INCLUDES += -I$(LIBRARIES_PATH) +INCLUDES += -I$(BSG_PLATFORM_PATH) + +LDFLAGS += -lstdc++ -lc -L$(BSG_PLATFORM_PATH) +CXXFLAGS += -O3 $(DEFINES) -fPIC -D_BSD_SOURCE -DGP0_ENABLE -DGP0_ADDR_BASE=0x40000000 +CFLAGS += -O3 $(DEFINES) -fPIC -D_BSD_SOURCE -DGP0_ENABLE -DGP0_ADDR_BASE=0x40000000 + +# each regression target needs to build its .o from a .c and .h of the +# same name +%.o: %.c + $(CC) -c -o $@ $< $(INCLUDES) $(CFLAGS) $(CDEFINES) + +# ... or a .cpp and .hpp of the same name +%.o: %.cpp + $(CXX) -c -o $@ $< $(INCLUDES) $(CXXFLAGS) $(CXXDEFINES) + +.PRECIOUS: %.o + +.PHONY: platform.compilation.clean +platform.compilation.clean: + rm -rf *.o + +compilation.clean: platform.compilation.clean diff --git a/libraries/platforms/zynqparrot-fpga/execution.mk b/libraries/platforms/zynqparrot-fpga/execution.mk new file mode 100644 index 000000000..a38d672d5 --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/execution.mk @@ -0,0 +1,40 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile fragment defines the rules that are used for executing +# applications on HammerBlade Platforms + +.PRECIOUS: exec.log saifgen.log +.PHONY: platform.execution.clean + +%.log: loader.o $(BSG_MANYCORE_KERNELS) + sudo env LD_LIBRARY_PATH=$(BSG_PLATFORM_PATH):$(LD_LIBRARY_PATH) ./$< $(C_ARGS) 2>&1 | tee $@ + +platform.execution.clean: + rm -rf exec.log + +execution.clean: platform.execution.clean diff --git a/libraries/platforms/zynqparrot-fpga/hardware.mk b/libraries/platforms/zynqparrot-fpga/hardware.mk new file mode 100644 index 000000000..95955d1c5 --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/hardware.mk @@ -0,0 +1,46 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# hardware.mk: Platform-specific HDL listing. +# +# For simulation platforms, it also describes how to build the +# simulation "libraries" that are required by CAD tools. +# +# This file should be included from bsg_replicant/hardware/hardware.mk. It checks +# BSG_PLATFORM_PATH, BASEJUMP_STL_DIR, BSG_MANYCORE_DIR, etc. + +VSOURCES += $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v +ASCII_TO_ROM_PY = $(BASEJUMP_STL_DIR)/bsg_mem/bsg_ascii_to_rom.py +$(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v: $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.rom + env python2 $(ASCII_TO_ROM_PY) $< bsg_bladerunner_configuration > $@ + +.PRECIOUS: $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v + +hardware.clean: machine.hardware.clean + +machine.hardware.clean: + rm -f $(BSG_MACHINE_PATH)/bsg_bladerunner_configuration.v diff --git a/libraries/platforms/zynqparrot-fpga/library.mk b/libraries/platforms/zynqparrot-fpga/library.mk new file mode 100644 index 000000000..fccd73e42 --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/library.mk @@ -0,0 +1,97 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +PLATFORM_CXXSOURCES += $(LIBRARIES_PATH)/features/profiler/noimpl/bsg_manycore_profiler.cpp +PLATFORM_CXXSOURCES += $(LIBRARIES_PATH)/features/tracer/noimpl/bsg_manycore_tracer.cpp +PLATFORM_CXXSOURCES += $(BSG_PLATFORM_PATH)/bsg_manycore_platform.cpp + +# aws-fpga does not provide a DMA feature. Therefore, we use the fragment in +# features/dma/noimpl/feature.mk that simply returns +# HB_MC_NO_IMPL for each function call. +include $(LIBRARIES_PATH)/features/dma/noimpl/feature.mk + +PLATFORM_OBJECTS += $(patsubst %cpp,%o,$(PLATFORM_CXXSOURCES)) +PLATFORM_OBJECTS += $(patsubst %c,%o,$(PLATFORM_CSOURCES)) + +PLATFORM_REGRESSION_OBJECTS += $(patsubst %cpp,%o,$(PLATFORM_REGRESSION_CXXSOURCES)) +PLATFORM_REGRESSION_OBJECTS += $(patsubst %c,%o,$(PLATFORM_REGRESSION_CSOURCES)) + +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES := -I$(LIBRARIES_PATH) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(BSG_PLATFORM_PATH) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/dma +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/profiler +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(LIBRARIES_PATH)/features/tracer +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(ZYNQPARROT_DIR)/cosim/include/common +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(ZYNQPARROT_DIR)/cosim/include/fpga +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): $(BSG_MACHINE_PATH)/bsg_manycore_machine.h +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(BSG_MACHINE_PATH) + +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): INCLUDES += -I$(CL_DIR)/../aws-fpga/sdk/userspace/include +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CFLAGS := -O3 -std=c11 -fPIC -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CFLAGS += -DGP0_ENABLE -DGP0_ADDR_BASE=0x400000000 +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CFLAGS += -DGP0_ADDR_WIDTH=10 -DGP0_DATA_WIDTH=32 +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CFLAGS += -DGP0_HIER_BASE=null +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CXXFLAGS := -O3 -std=c++11 -fPIC -D_BSD_SOURCE -D_GNU_SOURCE -D_DEFAULT_SOURCE $(INCLUDES) +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CXXFLAGS += -DGP0_ENABLE -DGP0_ADDR_BASE=0x400000000 +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CXXFLAGS += -DGP0_ADDR_WIDTH=10 -DGP0_DATA_WIDTH=32 +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): CXXFLAGS += -DGP0_HIER_BASE=null +$(PLATFORM_OBJECTS) $(PLATFORM_REGRESSION_OBJECTS): LDFLAGS = -fPIC +$(PLATFORM_REGRESSION_OBJECTS): LDFLAGS = -ldl + +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1.0: $(PLATFORM_OBJECTS) +$(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so.1.0: $(PLATFORM_REGRESSION_OBJECTS) + +# Mirror the extensions linux installation in /usr/lib provides so +# that we can use -lbsg_manycore_runtime +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1: %: %.0 + ln -sf $@.0 $@ + +$(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.so.1: %: %.0 + ln -sf $@.0 $@ + +$(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so.1: %: %.0 + ln -sf $@.0 $@ + +$(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so: %: %.1 + ln -sf $@.1 $@ + +$(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.so: %: %.1 + ln -sf $@.1 $@ + +$(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so: %: %.1 + ln -sf $@.1 $@ + +.PHONY: platform.clean install uninstall +platform.clean: + rm -f $(PLATFORM_OBJECTS) + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so.1 + rm -f $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so* + rm -f $(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.so* + +libraries.clean: platform.clean + diff --git a/libraries/platforms/zynqparrot-fpga/link.mk b/libraries/platforms/zynqparrot-fpga/link.mk new file mode 100644 index 000000000..8e0264077 --- /dev/null +++ b/libraries/platforms/zynqparrot-fpga/link.mk @@ -0,0 +1,63 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This Makefile Fragment defines rules for linking object files for native +# regression tests + +# hardware.mk is the file list for the simulation RTL. It includes the +# platform specific hardware.mk file. +include $(HARDWARE_PATH)/hardware.mk + +# libraries.mk defines how to build libbsg_manycore_runtime.so, which is +# pre-linked against all other simulation binaries. +include $(LIBRARIES_PATH)/libraries.mk + +ORANGE=\033[0;33m +RED=\033[0;31m +NC=\033[0m + +LDFLAGS += -L$(BSG_PLATFORM_PATH) +LDFLAGS += -lbsg_manycore_runtime -lbsg_manycore_regression -lbsgmc_cuda_legacy_pod_repl -lm + +TEST_CSOURCES += $(filter %.c,$(TEST_SOURCES)) +TEST_CXXSOURCES += $(filter %.cpp,$(TEST_SOURCES)) +TEST_OBJECTS += $(TEST_CXXSOURCES:.cpp=.o) +TEST_OBJECTS += $(TEST_CSOURCES:.c=.o) + +REGRESSION_LIBRARIES += $(BSG_PLATFORM_PATH)/libbsgmc_cuda_legacy_pod_repl.so +REGRESSION_LIBRARIES += $(BSG_PLATFORM_PATH)/libbsg_manycore_runtime.so +REGRESSION_LIBRARIES += $(BSG_PLATFORM_PATH)/libbsg_manycore_regression.so + +loader.o: $(TEST_OBJECTS) $(REGRESSION_LIBRARIES) + $(CXX) -o $@ $^ $(LDFLAGS) $(CDEFINES) + +.PHONY: platform.link.clean +platform.link.clean: + rm -rf loader.o + +link.clean: platform.link.clean + diff --git a/machine.mk b/machine.mk index c6d0e549b..e2f671f2c 100644 --- a/machine.mk +++ b/machine.mk @@ -38,7 +38,7 @@ endif # To switch machines, simply switch the path of BSG_MACHINE_PATH to # another directory with a Makefile.machine.include file. -BSG_MACHINE_PATH ?= $(BSG_F1_DIR)/machines/pod_X1Y1_ruche_X16Y8_hbm_one_pseudo_channel +BSG_MACHINE_PATH ?= $(BSG_F1_DIR)/machines/baseline_v0_32_16 # Convert the machine path to an abspath override BSG_MACHINE_PATH := $(abspath $(BSG_MACHINE_PATH)) diff --git a/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel/Makefile.machine.include index 6311aa6ad..e6da7862b 100644 --- a/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel/Makefile.machine.include @@ -89,6 +89,7 @@ BSG_MACHINE_POD_TILES_SUBARRAY_X = 1 BSG_MACHINE_POD_TILES_SUBARRAY_Y = 1 # Host Coordinate (Rarely Changed) +# For true host BSG_MACHINE_HOST_COORD_X = 2 BSG_MACHINE_HOST_COORD_Y = 0 @@ -108,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel_blackparrot/Makefile.machine.include b/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel_blackparrot/Makefile.machine.include new file mode 100644 index 000000000..11d46f773 --- /dev/null +++ b/machines/pod_X1Y1_mesh_X2Y2_hbm_one_pseudo_channel_blackparrot/Makefile.machine.include @@ -0,0 +1,148 @@ +# Copyright (c) 2019, University of Washington All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this list +# of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# Neither the name of the copyright holder nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +############################################################################################ +# pod_X1Y1_ruche_X16Y8_hbm_one_pseudo_channel # +# 1 pod # +# 128 RISC-V Tiles per pod, 16 tiles wide, 8 tiles tall # +# Last level caches on the top and bottom of each column # +# Each last-level cache is mapped to a separate HBM bank # +# There is one HBM Pseudochannel channel per pod. # +# There is a vanilla, 2D mesh network augmented with Ruche links # +# This configuration mimics a GPU. See the mem sys params # +############################################################################################ + +# Change these parameters to define your machine. All other parameters should remain constant. +BSG_MACHINE_CHIP_ID = 15ca2022 + +# Chip Pod Dimensions +BSG_MACHINE_PODS_X = 1 +BSG_MACHINE_PODS_Y = 1 + +# 1.5 GHz Core Clock +BSG_MACHINE_PODS_CYCLE_TIME_PS = 666 + +# Heterogeneous tile composition. Must be a 1-d array equal to the +# number of tiles, or shorthand (default:0) +# 0 is for Vanilla Core (RV32). +# Anything else should be described here :) +BSG_MACHINE_HETERO_TYPE_VEC = default:0 + +# Network Parameters +BSG_MACHINE_NETWORK_CFG = e_network_mesh +BSG_MACHINE_RUCHE_FACTOR_X = 1 +BSG_MACHINE_BARRIER_RUCHE_FACTOR_X = 1 +BSG_MACHINE_WH_RUCHE_FACTOR = 1 + +# Memory System Parameters +BSG_MACHINE_DRAM_INCLUDED = 1 +BSG_MACHINE_MEM_DRAMSIM3_PKG = bsg_dramsim3_hbm2_1gb_x64_32ba_pkg +BSG_MACHINE_MEM_CFG = e_vcache_hbm2 + +# Victim Cache Parameters +BSG_MACHINE_VCACHE_PER_DRAM_CHANNEL = 2 +BSG_MACHINE_VCACHE_SET = 64 +BSG_MACHINE_VCACHE_WAY = 4 +BSG_MACHINE_VCACHE_LINE_WORDS = 8 +BSG_MACHINE_VCACHE_STRIPE_WORDS = $(BSG_MACHINE_VCACHE_LINE_WORDS) +BSG_MACHINE_VCACHE_WORD_TRACKING = 0 +# Only applies to Non-blocking Cache +BSG_MACHINE_VCACHE_MISS_FIFO_ELS = 32 + +# Number of vcache tile rows in a cache pod on either side of a tile pod +BSG_MACHINE_POD_VCACHE_NUM_ROWS = 1 + +# NOC Coordinate Widths (Rarely Changed) +BSG_MACHINE_NOC_COORD_X_WIDTH = 7 +BSG_MACHINE_NOC_COORD_Y_WIDTH = 7 + +# Pod Tile Dimensions (Rarely Changed) +BSG_MACHINE_POD_TILES_X = 2 +BSG_MACHINE_POD_TILES_Y = 2 + +# Pod Tile subarray dimensions (Rarely changed, for physical design only) +BSG_MACHINE_POD_TILES_SUBARRAY_X = 1 +BSG_MACHINE_POD_TILES_SUBARRAY_Y = 1 + +# Host Coordinate (Rarely Changed) +BSG_MACHINE_HOST_COORD_X = 3 +BSG_MACHINE_HOST_COORD_Y = 6 + +BSG_MACHINE_HOST_X_CORD = $(BSG_MACHINE_HOST_COORD_X) +BSG_MACHINE_HOST_Y_CORD = $(BSG_MACHINE_HOST_COORD_Y) + +# Manycore Origin (Rarely Changed) +BSG_MACHINE_ORIGIN_COORD_X = 2 +BSG_MACHINE_ORIGIN_COORD_Y = 2 + +# Cache-DRAM Interface Width (Rarely Changed) +# TODO: change this to match the HBM channel data rate +BSG_MACHINE_VCACHE_DMA_DATA_WIDTH = 32 + +# IO flow control parameters. (Rarely Changed) +BSG_MACHINE_IO_EP_CREDITS = 32 +BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) +BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) + +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 1 + +##################### Constants and Computations ##################### + +# Aliases required for memsys.mk, and others. +# Specific to the HBM2E chip we're modeling (8GB, 4-stack/8-channel) +__BSG_MACHINE_DRAMSIM3_CHIP_SIZE_IN_WORDS := $(shell echo 2^28 | bc) # 1GB +__BSG_MACHINE_DRAMSIM3_CHIP_CH_SIZE_IN_WORDS := $(shell echo $(__BSG_MACHINE_DRAMSIM3_CHIP_SIZE_IN_WORDS)/1 | bc) + +BSG_MACHINE_POD_TILES := $(shell echo $(BSG_MACHINE_POD_TILES_X)*$(BSG_MACHINE_POD_TILES_Y) | bc) +BSG_MACHINE_NUM_PODS := $(shell echo $(BSG_MACHINE_PODS_X)*$(BSG_MACHINE_PODS_Y) | bc) +BSG_MACHINE_NUM_VCACHE := $(shell echo $(BSG_MACHINE_POD_TILES_X)*2*$(BSG_MACHINE_NUM_PODS) | bc) +BSG_MACHINE_DRAM_CHANNELS := $(shell echo $(BSG_MACHINE_NUM_VCACHE)/$(BSG_MACHINE_VCACHE_PER_DRAM_CHANNEL) | bc) + +BSG_MACHINE_DRAM_WORDS := $(shell echo $(__BSG_MACHINE_DRAMSIM3_CHIP_CH_SIZE_IN_WORDS)*$(BSG_MACHINE_DRAM_CHANNELS) | bc) +BSG_MACHINE_DRAM_PER_CACHE_WORDS = $(shell echo "$(BSG_MACHINE_DRAM_WORDS) / $(BSG_MACHINE_NUM_VCACHE)" | bc) + +# Aliases Required for BSG Manycore +BSG_MACHINE_GLOBAL_X = $(BSG_MACHINE_POD_TILES_X) +BSG_MACHINE_GLOBAL_Y = $(BSG_MACHINE_POD_TILES_Y) +BSG_MACHINE_DRAM_BANK_WORDS = $(BSG_MACHINE_DRAM_PER_CACHE_WORDS) +BSG_MACHINE_DRAM_BANK_SIZE_WORDS = $(BSG_MACHINE_DRAM_BANK_WORDS) +BSG_MACHINE_VCACHE_BLOCK_SIZE_WORDS = $(BSG_MACHINE_VCACHE_LINE_WORDS) +BSG_MACHINE_NUM_VCACHE_ROWS = $(BSG_MACHINE_POD_VCACHE_NUM_ROWS) + +BSG_MACHINE_MAX_EPA_WIDTH = 28 +BSG_MACHINE_DATA_WIDTH = 32 + +# Define BSG_MACHINE_NAME +BSG_MACHINE_NAME =BSG_PX$(BSG_MACHINE_PODS_X)PY$(BSG_MACHINE_PODS_Y) +BSG_MACHINE_NAME :=$(BSG_MACHINE_NAME)_DX$(BSG_MACHINE_POD_TILES_X)DY$(BSG_MACHINE_POD_TILES_Y) +BSG_MACHINE_NAME :=$(BSG_MACHINE_NAME)_$(BSG_MACHINE_MEM_CFG:e_%=%) + +# This flag has to be always 0 by default. Conditional +# assignment allows user to set this flag through +# environment when required. +BSG_MACHINE_BRANCH_TRACE_EN ?= 0 diff --git a/machines/pod_X1Y1_ruche_X16Y16_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X16Y16_hbm_one_pseudo_channel/Makefile.machine.include index d8b18272b..38dd7f849 100644 --- a/machines/pod_X1Y1_ruche_X16Y16_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X16Y16_hbm_one_pseudo_channel/Makefile.machine.include @@ -109,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X16Y8_hbm/Makefile.machine.include b/machines/pod_X1Y1_ruche_X16Y8_hbm/Makefile.machine.include index 3d94119e5..91acfa0fa 100644 --- a/machines/pod_X1Y1_ruche_X16Y8_hbm/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X16Y8_hbm/Makefile.machine.include @@ -106,6 +106,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X16Y8_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X16Y8_hbm_one_pseudo_channel/Makefile.machine.include index 98c0e03fb..e9fcbf3ef 100644 --- a/machines/pod_X1Y1_ruche_X16Y8_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X16Y8_hbm_one_pseudo_channel/Makefile.machine.include @@ -109,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X32Y16_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X32Y16_hbm_one_pseudo_channel/Makefile.machine.include index d1dbf1b79..652abc767 100644 --- a/machines/pod_X1Y1_ruche_X32Y16_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X32Y16_hbm_one_pseudo_channel/Makefile.machine.include @@ -109,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X4Y2_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X4Y2_hbm_one_pseudo_channel/Makefile.machine.include index 3169b30ff..64bebf6e2 100644 --- a/machines/pod_X1Y1_ruche_X4Y2_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X4Y2_hbm_one_pseudo_channel/Makefile.machine.include @@ -109,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X4Y4_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X4Y4_hbm_one_pseudo_channel/Makefile.machine.include index eee03dda2..f978616a7 100644 --- a/machines/pod_X1Y1_ruche_X4Y4_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X4Y4_hbm_one_pseudo_channel/Makefile.machine.include @@ -109,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X8Y4_hbm/Makefile.machine.include b/machines/pod_X1Y1_ruche_X8Y4_hbm/Makefile.machine.include index d846b81b3..44e9e7051 100644 --- a/machines/pod_X1Y1_ruche_X8Y4_hbm/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X8Y4_hbm/Makefile.machine.include @@ -106,6 +106,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X8Y4_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X8Y4_hbm_one_pseudo_channel/Makefile.machine.include index a512bdefb..317af2809 100644 --- a/machines/pod_X1Y1_ruche_X8Y4_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X8Y4_hbm_one_pseudo_channel/Makefile.machine.include @@ -108,6 +108,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X1Y1_ruche_X8Y8_hbm_one_pseudo_channel/Makefile.machine.include b/machines/pod_X1Y1_ruche_X8Y8_hbm_one_pseudo_channel/Makefile.machine.include index 35f50a67d..64d536fc4 100644 --- a/machines/pod_X1Y1_ruche_X8Y8_hbm_one_pseudo_channel/Makefile.machine.include +++ b/machines/pod_X1Y1_ruche_X8Y8_hbm_one_pseudo_channel/Makefile.machine.include @@ -109,6 +109,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X2Y2_ruche_X16Y8_hbm/Makefile.machine.include b/machines/pod_X2Y2_ruche_X16Y8_hbm/Makefile.machine.include index 766260693..a5b823f96 100644 --- a/machines/pod_X2Y2_ruche_X16Y8_hbm/Makefile.machine.include +++ b/machines/pod_X2Y2_ruche_X16Y8_hbm/Makefile.machine.include @@ -106,6 +106,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/machines/pod_X4Y4_ruche_X16Y8_hbm/Makefile.machine.include b/machines/pod_X4Y4_ruche_X16Y8_hbm/Makefile.machine.include index 494149808..5788a35a0 100644 --- a/machines/pod_X4Y4_ruche_X16Y8_hbm/Makefile.machine.include +++ b/machines/pod_X4Y4_ruche_X16Y8_hbm/Makefile.machine.include @@ -106,6 +106,9 @@ BSG_MACHINE_IO_EP_CREDITS = 32 BSG_MACHINE_IO_HOST_CREDITS = $(BSG_MACHINE_IO_EP_CREDITS) BSG_MACHINE_IO_REMOTE_LOAD_CAP = $(BSG_MACHINE_IO_EP_CREDITS) +# Host type 0 = off-chip 1 = BlackParrot +BSG_MACHINE_HOST_TYPE = 0 + ##################### Constants and Computations ##################### # Aliases required for memsys.mk, and others. diff --git a/platform.mk b/platform.mk index 73d1e8d4e..5ef4b7f0c 100644 --- a/platform.mk +++ b/platform.mk @@ -44,7 +44,7 @@ endif # We default to simulating the AWS machine uinsg Synopsys VCS-MX, # HOWEVER, if VCS_HOME is not defined then we will assume that # VCS/VCS-MX is not installed and try fall-back options -BSG_PLATFORM ?= bigblade-vcs +BSG_PLATFORM ?= dpi-vcs # FIRST check if BSG_PLATFORM is valid. It should match of the # directories in libraries/platforms