This source file includes following definitions.
- init_sim
- write_memory
- read_memory
- send_message
- dataLen
- halide_hexagon_remote_initialize_kernels_v3
- halide_hexagon_remote_get_symbol_v4
- halide_hexagon_remote_run
- halide_hexagon_remote_release_kernels_v2
- halide_hexagon_host_malloc_init
- halide_hexagon_host_malloc_deinit
- halide_hexagon_host_malloc
- halide_hexagon_host_free
- halide_hexagon_remote_poll_profiler_state
#include <vector>
#include <sstream>
#include <cassert>
#include <memory>
#include <mutex>
#include <HalideRuntime.h>
#include <HexagonWrapper.h>
#include "sim_protocol.h"
#ifdef _MSC_VER
#define HALIDE_EXPORT __declspec(dllexport)
#else
#define HALIDE_EXPORT
#endif
typedef unsigned int handle_t;
std::unique_ptr<HexagonWrapper> sim;
bool debug_mode = false;
bool use_dlopenbuf = true;
int init_sim() {
    if (sim) return 0;
    sim = std::unique_ptr<HexagonWrapper>(new HexagonWrapper(HEX_CPU_V60));
    HEXAPI_Status status = HEX_STAT_SUCCESS;
    
    const char *sim_remote_path = getenv("HL_HEXAGON_SIM_REMOTE");
    if (!sim_remote_path || !sim_remote_path[0]) {
        
        
        sim_remote_path = "hexagon_sim_remote";
    }
    status = sim->ConfigureExecutableBinary(sim_remote_path);
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::ConfigureExecutableBinary failed: %d\n", status);
        return -1;
    }
    status = sim->ConfigureNULLPointerBehavior(HEX_NULLPTR_FATAL);
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::ConfigureNULLPointerBehavior failed: %d\n", status);
        return -1;
    }
    
    
    const char *memfill = getenv("HL_HEXAGON_MEMFILL");
    if (memfill && memfill[0] != 0) {
        status = sim->ConfigureMemFill(atoi(memfill));
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::ConfigureMemFill failed: %d\n", status);
            return -1;
        }
    }
    const char *timing = getenv("HL_HEXAGON_TIMING");
    if (timing && timing[0] != 0) {
        status = sim->ConfigureTimingMode(HEX_TIMING);
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::ConfigureTimingMode failed: %d\n", status);
            return -1;
        }
    }
    
    const char *T = getenv("HL_HEXAGON_SIM_MIN_TRACE");
    if (T && T[0] != 0) {
        status = sim->SetTracing(HEX_TRACE_PC_MIN, T);
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::SetTracing MIN failed: %d\n", status);
            return -1;
        }
    } else {
        const char *T = getenv("HL_HEXAGON_SIM_TRACE");
        if (T && T[0] != 0) {
            status = sim->SetTracing(HEX_TRACE_PC, T);
            if (status != HEX_STAT_SUCCESS) {
                printf("HexagonWrapper::SetTracing failed: %d\n", status);
                return -1;
            }
        }
    }
    
    int pnum = 0;
    const char *s = getenv("HL_HEXAGON_SIM_DBG_PORT");
    if (s && (pnum = atoi(s))) {
        printf("Debugger port: %d\n", pnum);
        status = sim->ConfigureRemoteDebug(pnum);
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::ConfigureRemoteDebug failed: %d\n", status);
            return -1;
        } else {
            debug_mode = true;
        }
    }
    
    
    
    const char *use = getenv("HL_HEXAGON_USE_DLOPENBUF");
    if (use && !atoi(use)) {
        use_dlopenbuf = false;
    }
    status = sim->EndOfConfiguration();
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::EndOfConfiguration failed: %d\n", status);
        return -1;
    }
    status = sim->LoadExecutableBinary();
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::LoadExecutableBinary failed: %d\n", status);
        return -1;
    }
    return 0;
}
int write_memory(int dest, const void *src, int size) {
    assert(sim);
    while (size > 0) {
        
        
        
        HEX_8u_t src_chunk;
        int chunk_size;
        if (size >= 8) {
            src_chunk = *reinterpret_cast<const HEX_8u_t*>(src);
            chunk_size = 8;
        } else if (size >= 4) {
            src_chunk = *reinterpret_cast<const HEX_4u_t*>(src);
            chunk_size = 4;
        } else if (size >= 2) {
            src_chunk = *reinterpret_cast<const HEX_2u_t*>(src);
            chunk_size = 2;
        } else {
            src_chunk = *reinterpret_cast<const HEX_1u_t*>(src);
            chunk_size = 1;
        }
        HEXAPI_Status status = sim->WriteMemory(dest, chunk_size, src_chunk);
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::WriteMemory failed: %d\n", status);
            return -1;
        }
        size -= chunk_size;
        dest += chunk_size;
        src = reinterpret_cast<const char *>(src) + chunk_size;
    }
    return 0;
}
int read_memory(void *dest, int src, int size) {
    assert(sim);
    while (size > 0) {
        
        int next = 1;
        if (size >= 8) next = 8;
        else if (size >= 4) next = 4;
        else if (size >= 2) next = 2;
        HEXAPI_Status status = sim->ReadMemory(src, next, dest);
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::ReadMemory failed: %d\n", status);
            return -1;
        }
        size -= next;
        src += next;
        dest = reinterpret_cast<char *>(dest) + next;
    }
    return 0;
}
int profiler_current_func;
int send_message(int msg, const std::vector<int> &arguments) {
    assert(sim);
    HEXAPI_Status status;
    HEX_4u_t remote_msg = 0;
    status = sim->ReadSymbolValue("rpc_call", &remote_msg);
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::ReadSymbolValue(rpcmsg) failed: %d\n", status);
        return -1;
    }
    if (write_memory(remote_msg, &msg, 4) != 0) { return -1; }
    
    for (size_t i = 0; i < arguments.size(); i++) {
        HEX_4u_t remote_arg = 0;
        std::string rpc_arg = "rpc_arg" + std::to_string(i);
        status = sim->ReadSymbolValue(rpc_arg.c_str(), &remote_arg);
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::ReadSymbolValue(%s) failed: %d\n", rpc_arg.c_str(), status);
            return -1;
        }
        if (write_memory(remote_arg, &arguments[i], 4) != 0) { return -1; }
    }
    HEX_4u_t remote_ret = 0;
    status = sim->ReadSymbolValue("rpc_ret", &remote_ret);
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::ReadSymbolValue(rpc_ret) failed: %d\n", status);
        return -1;
    }
    
    
    
    HEX_4u_t remote_profiler_current_func_addr_addr = 0;
    HEX_4u_t remote_profiler_current_func_addr = 0;
    status = sim->ReadSymbolValue("profiler_current_func_addr",
                                  &remote_profiler_current_func_addr_addr);
    if (status != HEX_STAT_SUCCESS) {
        printf("HexagonWrapper::ReadSymbolValue(profiler_current_func_addr) failed: %d\n", status);
        return -1;
    }
    if (read_memory(&remote_profiler_current_func_addr,
                    remote_profiler_current_func_addr_addr,
                    sizeof(HEX_4u_t))) {
        return -1;
    }
    HEXAPI_CoreState state;
    
    
    if (msg == Message::Break || (debug_mode && (msg == Message::Run))) {
        
        
        HEX_4u_t result;
        state = sim->Run(&result);
        if (state != HEX_CORE_FINISHED) {
            printf("HexagonWrapper::Run failed: %d\n", state);
            return -1;
        }
        return 0;
    } else {
        
        
        
        do {
            HEX_4u_t cycles;
            state = sim->Step(1000, &cycles);
            if (read_memory(&msg, remote_msg, 4) != 0) {
                return -1;
            }
            if (msg == Message::None) {
                HEX_4u_t ret = 0;
                if (read_memory(&ret, remote_ret, 4)) {
                    return -1;
                }
                return ret;
            }
            
            read_memory(&profiler_current_func, remote_profiler_current_func_addr, sizeof(int));
        } while (state == HEX_CORE_SUCCESS);
        printf("HexagonWrapper::StepTime failed: %d\n", state);
        return -1;
    }
}
struct host_buffer {
    unsigned char *data;
    int dataLen;
};
class remote_buffer {
public:
    int data;
    int dataLen;
    remote_buffer() : data(0), dataLen(0) {}
    remote_buffer(int dataLen) : dataLen(dataLen) {
        if (dataLen > 0) {
            data = send_message(Message::Alloc, {dataLen});
            if (data == 0) {
                printf("Failed to allocate %d bytes in the Hexagon simulation.\n", dataLen);
            }
        } else {
            data = 0;
        }
    }
    remote_buffer(const void *data, int dataLen) : remote_buffer(dataLen) {
        if (this->data != 0) {
            
            
            write_memory(this->data, data, dataLen);
        }
    }
    remote_buffer(const host_buffer &host_buf) : remote_buffer(host_buf.data, host_buf.dataLen) {}
    ~remote_buffer() {
        if (data != 0) {
            send_message(Message::Free, {data});
        }
    }
    
    remote_buffer(remote_buffer &&move) : remote_buffer() {
        std::swap(data, move.data);
        std::swap(dataLen, move.dataLen);
    }
    remote_buffer &operator=(remote_buffer &&move) {
        std::swap(data, move.data);
        std::swap(dataLen, move.dataLen);
        return *this;
    }
    remote_buffer(const remote_buffer &) = delete;
    remote_buffer &operator=(const remote_buffer &) = delete;
};
std::mutex mutex;
extern "C" {
HALIDE_EXPORT
int halide_hexagon_remote_initialize_kernels_v3(const unsigned char *code, int codeLen, handle_t *module_ptr) {
    std::lock_guard<std::mutex> guard(mutex);
    int ret = init_sim();
    if (ret != 0) return -1;
    
    remote_buffer remote_code(code, codeLen);
    remote_buffer remote_module_ptr(module_ptr, 4);
    
    ret = send_message(Message::InitKernels, {remote_code.data, codeLen, use_dlopenbuf, remote_module_ptr.data});
    if (ret != 0) return ret;
    
    ret = read_memory(module_ptr, remote_module_ptr.data, 4);
    return ret;
}
HALIDE_EXPORT
int halide_hexagon_remote_get_symbol_v4(handle_t module_ptr, const char* name, int nameLen, handle_t* sym) {
    std::lock_guard<std::mutex> guard(mutex);
    assert(sim);
    
    remote_buffer remote_name(name, nameLen);
    
    *sym = send_message(Message::GetSymbol, {static_cast<int>(module_ptr), remote_name.data, nameLen, use_dlopenbuf});
    return *sym != 0 ? 0 : -1;
}
HALIDE_EXPORT
int halide_hexagon_remote_run(handle_t module_ptr, handle_t function,
                              const host_buffer *input_buffersPtrs, int input_buffersLen,
                              host_buffer *output_buffersPtrs, int output_buffersLen,
                              const host_buffer *input_scalarsPtrs, int input_scalarsLen) {
    std::lock_guard<std::mutex> guard(mutex);
    assert(sim);
    std::vector<remote_buffer> remote_input_buffers;
    std::vector<remote_buffer> remote_output_buffers;
    std::vector<remote_buffer> remote_input_scalars;
    for (int i = 0; i < input_buffersLen; i++) {
        remote_input_buffers.emplace_back(input_buffersPtrs[i]);
    }
    for (int i = 0; i < output_buffersLen; i++) {
        remote_output_buffers.emplace_back(output_buffersPtrs[i]);
    }
    for (int i = 0; i < input_scalarsLen; i++) {
        remote_input_scalars.emplace_back(input_scalarsPtrs[i]);
    }
    
    remote_buffer remote_input_buffersPtrs(&remote_input_buffers[0], input_buffersLen * sizeof(remote_buffer));
    remote_buffer remote_output_buffersPtrs(&remote_output_buffers[0], output_buffersLen * sizeof(remote_buffer));
    remote_buffer remote_input_scalarsPtrs(&remote_input_scalars[0], input_scalarsLen * sizeof(remote_buffer));
    HEX_8u_t cycles_begin = 0;
    sim->GetSimulatedCycleCount(&cycles_begin);
    
    int ret = send_message(
        Message::Run,
        {static_cast<int>(module_ptr), static_cast<int>(function),
         remote_input_buffersPtrs.data, input_buffersLen,
         remote_output_buffersPtrs.data, output_buffersLen,
         remote_input_scalarsPtrs.data, input_scalarsLen});
    if (ret != 0) return ret;
    HEX_8u_t cycles_end = 0;
    sim->GetSimulatedCycleCount(&cycles_end);
    if (getenv("HL_HEXAGON_SIM_CYCLES")) {
        int cycles = static_cast<int>(cycles_end - cycles_begin);
        printf("Hexagon simulator executed function 0x%x in %d cycles\n", function, cycles);
    }
    
    for (int i = 0; i < output_buffersLen; i++) {
        ret = read_memory(output_buffersPtrs[i].data, remote_output_buffers[i].data, output_buffersPtrs[i].dataLen);
        if (ret != 0) return ret;
    }
    return ret;
}
HALIDE_EXPORT
int halide_hexagon_remote_release_kernels_v2(handle_t module_ptr) {
    std::lock_guard<std::mutex> guard(mutex);
    if (!sim) {
        
        
        return 0;
    }
    
    if (getenv("HL_HEXAGON_SIM_STATS")) {
        char Buf[4096];
        HEXAPI_Status status = sim->EmitPerfStatistics(0, 0, 0, 0, Buf, sizeof(Buf));
        if (status != HEX_STAT_SUCCESS) {
            printf("HexagonWrapper::EmitStatistics failed: %d\n", status);
        } else {
            
            printf("%s\n", Buf);
        }
    }
    return send_message(Message::ReleaseKernels, {static_cast<int>(module_ptr), use_dlopenbuf});
}
HALIDE_EXPORT
void halide_hexagon_host_malloc_init() {
}
HALIDE_EXPORT
void halide_hexagon_host_malloc_deinit() {
}
HALIDE_EXPORT
void *halide_hexagon_host_malloc(size_t x) {
    
    const size_t alignment = 4096;
    void *orig = malloc(x + alignment);
    if (orig == NULL) {
        return NULL;
    }
    
    void *ptr = (void *)(((size_t)orig + alignment + sizeof(void*) - 1) & ~(alignment - 1));
    ((void **)ptr)[-1] = orig;
    return ptr;
}
HALIDE_EXPORT
void halide_hexagon_host_free(void *ptr) {
    free(((void**)ptr)[-1]);
}
HALIDE_EXPORT
int halide_hexagon_remote_poll_profiler_state(int *func, int *threads) {
    
    
    *func = profiler_current_func;
    *threads = 1;
    return 0;
}
}