/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /*! * \file sim_tlpp.cc * \brief simulate core level pipe line parallism logic. */ #include <vta/sim_tlpp.h> TlppVerify::TlppVerify() { done_ = 0; } void TlppVerify::Clear() { fsim_handle_ = nullptr; run_fsim_function_ = nullptr; for (int i = 0; i < COREMAX; i++) { while (insnq_array_[i].size()) { insnq_array_[i].pop(); } } done_ = 0; } uint64_t TlppVerify::GetOperationCode(const VTAGenericInsn *insn) { const VTAMemInsn* mem = reinterpret_cast<const VTAMemInsn*>(insn); return mem->opcode; } CORE_TYPE TlppVerify::GetCoreType(uint64_t operation_code, const VTAGenericInsn *insn) { CORE_TYPE core_type = COREGEMM; const VTAMemInsn* mem = reinterpret_cast<const VTAMemInsn*>(insn); switch (operation_code) { case VTA_OPCODE_GEMM: case VTA_OPCODE_ALU: core_type = COREGEMM; break; case VTA_OPCODE_LOAD: if (mem->memory_type == VTA_MEM_ID_INP|| mem->memory_type == VTA_MEM_ID_WGT) { core_type = CORELOAD; } break; case VTA_OPCODE_STORE: core_type = CORESTORE; break; default: break; } return core_type; } bool TlppVerify::DependencyProcess(bool before_run, bool pop_prev, bool pop_next, bool push_prev, bool push_next, Dep_q_t *pop_prev_q, Dep_q_t *pop_next_q, Dep_q_t *push_prev_q, Dep_q_t *push_next_q, CORE_TYPE push_to_prev_q_indx, CORE_TYPE push_to_next_q_indx) { int val = 1; if (before_run) { if (pop_prev && pop_prev_q->size() == 0) { return false; } if (pop_next && pop_next_q->size() == 0) { return false; } if (pop_next) pop_next_q->pop(); if (pop_prev) pop_prev_q->pop(); } else { if (push_prev) { push_prev_q->push(val); dep_push_event_.push(push_to_prev_q_indx); } if (push_next) { push_next_q->push(val); dep_push_event_.push(push_to_next_q_indx); } } return true; } bool TlppVerify::InsnDependencyCheck(const VTAGenericInsn *insn, bool before_run) { const VTAMemInsn* mem = reinterpret_cast<const VTAMemInsn*>(insn); bool pop_prev = mem->pop_prev_dep; bool pop_next = mem->pop_next_dep; bool push_prev = mem->push_prev_dep; bool push_next = mem->push_next_dep; CORE_TYPE core_type = GetCoreType(GetOperationCode(insn), insn); bool bcheck = false; switch (core_type) { case COREGEMM: bcheck = DependencyProcess(before_run, pop_prev, pop_next, push_prev, push_next, &l2g_q_, &s2g_q_, &g2l_q_, &g2s_q_, CORELOAD, CORESTORE); break; case CORELOAD: bcheck = DependencyProcess(before_run, pop_prev, pop_next, push_prev, push_next, nullptr, &g2l_q_, nullptr, &l2g_q_, COREMAX, COREGEMM); break; case CORESTORE: bcheck = DependencyProcess(before_run, pop_prev, pop_next, push_prev, push_next, &g2s_q_, nullptr, &s2g_q_, nullptr, COREGEMM, COREMAX); break; case COREMAX: assert(0); break; } return bcheck; } void TlppVerify::CoreRun(CORE_TYPE core_type) { const VTAGenericInsn *insn = PickFrontInsn(core_type); while (insn) { /*! * Check need to read any dependency queue for wait. */ if (!InsnDependencyCheck(insn, true)) { break; } /*! * Execute the instruction. */ run_fsim_function_(insn, fsim_handle_); /*! *check if need to write any dependency queue for notify. */ InsnDependencyCheck(insn, false); /*! * If instruction is FINISH set done flag. * notification. */ done_ = GetOperationCode(insn) == VTA_OPCODE_FINISH; if (debug_) { printf("this is thread for %s\n", GetCoreTypeName(core_type)); } ConsumeFrontInsn(core_type); insn = PickFrontInsn(core_type); } return; } void TlppVerify::EventProcess(void) { while (dep_push_event_.size()) { CORE_TYPE core_type = dep_push_event_.front(); dep_push_event_.pop(); CoreRun(core_type); } } void TlppVerify::TlppSynchronization(Run_Function run_function, void *fsim_handle, bool debug) { fsim_handle_ = fsim_handle; run_fsim_function_ = run_function; debug_ = debug; done_ = 0; do { /* * Pick a random core to run first. */ unsigned int seed = time(NULL); uint8_t core_start = rand_r(&seed)%COREMAX; for (int i = 0; i < COREMAX; i++) { CoreRun(static_cast<CORE_TYPE>((core_start + i) % COREMAX)); } EventProcess(); }while (!done_); Clear(); return; } void TlppVerify::TlppPushInsn(const VTAGenericInsn *insn) { uint64_t operation_code = GetOperationCode(insn); CORE_TYPE core_type = GetCoreType(operation_code, insn); insnq_array_[core_type].push(static_cast<const void *>(insn)); return; } const VTAGenericInsn *TlppVerify::PickFrontInsn(uint64_t core_type) { const void *return_value = nullptr; if (insnq_array_[core_type].size()) { return_value = insnq_array_[core_type].front(); } return reinterpret_cast<const VTAGenericInsn *> (return_value); } void TlppVerify::ConsumeFrontInsn(uint64_t core_type) { if (insnq_array_[core_type].size()) { insnq_array_[core_type].pop(); } }