Line 1... |
Line 1... |
/**
|
/*
|
* @file
|
* Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
|
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
*
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* @brief System Bus class declaration (AMBA or whatever).
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
*/
|
*/
|
|
|
#include "api_core.h"
|
#include <api_core.h>
|
#include "bus.h"
|
#include "bus.h"
|
#include "coreservices/icpuriscv.h"
|
#include "coreservices/icpugen.h"
|
|
|
namespace debugger {
|
namespace debugger {
|
|
|
/** Class registration in the Core */
|
/** Class registration in the Core */
|
REGISTER_CLASS(Bus)
|
REGISTER_CLASS(Bus)
|
|
|
Bus::Bus(const char *name)
|
Bus::Bus(const char *name)
|
: IService(name) {
|
: IService(name) {
|
registerInterface(static_cast<IBus *>(this));
|
registerInterface(static_cast<IMemoryOperation *>(this));
|
registerAttribute("MapList", &listMap_);
|
registerAttribute("DSU", &dsu_);
|
|
|
listMap_.make_list(0);
|
|
imap_.make_list(0);
|
|
RISCV_mutex_init(&mutexBAccess_);
|
RISCV_mutex_init(&mutexBAccess_);
|
RISCV_mutex_init(&mutexNBAccess_);
|
RISCV_mutex_init(&mutexNBAccess_);
|
memset(info_, 0, sizeof(info_));
|
idsu_ = 0;
|
}
|
}
|
|
|
Bus::~Bus() {
|
Bus::~Bus() {
|
RISCV_mutex_destroy(&mutexBAccess_);
|
RISCV_mutex_destroy(&mutexBAccess_);
|
RISCV_mutex_destroy(&mutexNBAccess_);
|
RISCV_mutex_destroy(&mutexNBAccess_);
|
}
|
}
|
|
|
void Bus::postinitService() {
|
void Bus::postinitService() {
|
|
if (dsu_.is_string()) {
|
|
idsu_ = static_cast<IDsuGeneric *>(
|
|
RISCV_get_service_iface(dsu_.to_string(), IFACE_DSU_GENERIC));
|
|
if (!idsu_) {
|
|
RISCV_debug("Can't find IDsuGeneric interface %s",
|
|
dsu_.to_string());
|
|
}
|
|
}
|
|
|
IMemoryOperation *imem;
|
IMemoryOperation *imem;
|
for (unsigned i = 0; i < listMap_.size(); i++) {
|
for (unsigned i = 0; i < listMap_.size(); i++) {
|
|
const AttributeType &dev = listMap_[i];
|
|
if (dev.is_string()) {
|
imem = static_cast<IMemoryOperation *>(RISCV_get_service_iface(
|
imem = static_cast<IMemoryOperation *>(RISCV_get_service_iface(
|
listMap_[i].to_string(), IFACE_MEMORY_OPERATION));
|
dev.to_string(), IFACE_MEMORY_OPERATION));
|
|
if (imem == 0) {
|
|
RISCV_error("Can't find slave device %s", dev.to_string());
|
|
continue;
|
|
}
|
|
map(imem);
|
|
} else if (dev.is_list() && dev.size() == 2) {
|
|
const AttributeType &devname = dev[0u];
|
|
const AttributeType &portname = dev[1];
|
|
imem = static_cast<IMemoryOperation *>(
|
|
RISCV_get_service_port_iface(devname.to_string(),
|
|
portname.to_string(),
|
|
IFACE_MEMORY_OPERATION));
|
if (imem == 0) {
|
if (imem == 0) {
|
RISCV_error("Can't find slave device %s", listMap_[i].to_string());
|
RISCV_error("Can't find slave device %s:%s",
|
|
dev[0u].to_string(), dev[1].to_string());
|
continue;
|
continue;
|
}
|
}
|
map(imem);
|
map(imem);
|
}
|
}
|
|
}
|
|
|
AttributeType clks;
|
AttributeType clks;
|
RISCV_get_clock_services(&clks);
|
RISCV_get_clock_services(&clks);
|
if (clks.size()) {
|
if (clks.size()) {
|
iclk0_ = static_cast<IClock *>(clks[0u].to_iface());
|
iclk0_ = static_cast<IClock *>(clks[0u].to_iface());
|
} else {
|
} else {
|
RISCV_error("CPUs not found", NULL);
|
RISCV_error("CPUs not found", NULL);
|
}
|
}
|
}
|
}
|
|
|
void Bus::map(IMemoryOperation *imemop) {
|
|
AttributeType t1(imemop);
|
|
imap_.add_to_list(&t1);
|
|
}
|
|
|
|
ETransStatus Bus::b_transport(Axi4TransactionType *trans) {
|
ETransStatus Bus::b_transport(Axi4TransactionType *trans) {
|
IMemoryOperation *imem;
|
|
bool unmapped = true;
|
|
ETransStatus ret = TRANS_OK;
|
ETransStatus ret = TRANS_OK;
|
|
uint32_t sz;
|
|
IMemoryOperation *memdev = 0;
|
|
|
RISCV_mutex_lock(&mutexBAccess_);
|
RISCV_mutex_lock(&mutexBAccess_);
|
|
|
for (unsigned i = 0; i < imap_.size(); i++) {
|
getMapedDevice(trans, &memdev, &sz);
|
imem = static_cast<IMemoryOperation *>(imap_[i].to_iface());
|
|
if (imem->getBaseAddress() <= trans->addr
|
|
&& trans->addr < (imem->getBaseAddress() + imem->getLength())) {
|
|
|
|
imem->b_transport(trans);
|
if (memdev == 0) {
|
unmapped = false;
|
RISCV_error("[%" RV_PRI64 "d] Blocking request to unmapped address "
|
break;
|
|
/// @todo Check memory overlapping
|
|
}
|
|
}
|
|
|
|
if (unmapped) {
|
|
RISCV_error("[%" RV_PRI64 "d] Read from unmapped address "
|
|
"%08" RV_PRI64 "x", iclk0_->getStepCounter(), trans->addr);
|
"%08" RV_PRI64 "x", iclk0_->getStepCounter(), trans->addr);
|
memset(trans->rpayload.b8, 0xFF, trans->xsize);
|
memset(trans->rpayload.b8, 0xFF, trans->xsize);
|
ret = TRANS_ERROR;
|
ret = TRANS_ERROR;
|
} else {
|
} else {
|
|
memdev->b_transport(trans);
|
RISCV_debug("[%08" RV_PRI64 "x] => [%08x %08x]",
|
RISCV_debug("[%08" RV_PRI64 "x] => [%08x %08x]",
|
trans->addr,
|
trans->addr,
|
trans->rpayload.b32[1], trans->rpayload.b32[0]);
|
trans->rpayload.b32[1], trans->rpayload.b32[0]);
|
}
|
}
|
|
|
// Update Bus utilization counters:
|
// Update Bus utilization counters:
|
|
if (idsu_) {
|
if (trans->action == MemAction_Read) {
|
if (trans->action == MemAction_Read) {
|
info_[trans->source_idx].r_cnt++;
|
idsu_->incrementRdAccess(trans->source_idx);
|
} else if (trans->action == MemAction_Write) {
|
} else if (trans->action == MemAction_Write) {
|
info_[trans->source_idx].w_cnt++;
|
idsu_->incrementWrAccess(trans->source_idx);
|
|
}
|
}
|
}
|
RISCV_mutex_unlock(&mutexBAccess_);
|
RISCV_mutex_unlock(&mutexBAccess_);
|
return ret;
|
return ret;
|
}
|
}
|
|
|
ETransStatus Bus::nb_transport(Axi4TransactionType *trans,
|
ETransStatus Bus::nb_transport(Axi4TransactionType *trans,
|
IAxi4NbResponse *cb) {
|
IAxi4NbResponse *cb) {
|
IMemoryOperation *imem;
|
|
bool unmapped = true;
|
|
ETransStatus ret = TRANS_OK;
|
ETransStatus ret = TRANS_OK;
|
|
IMemoryOperation *memdev = 0;
|
|
uint32_t sz;
|
|
|
RISCV_mutex_lock(&mutexNBAccess_);
|
RISCV_mutex_lock(&mutexNBAccess_);
|
|
|
for (unsigned i = 0; i < imap_.size(); i++) {
|
getMapedDevice(trans, &memdev, &sz);
|
imem = static_cast<IMemoryOperation *>(imap_[i].to_iface());
|
|
if (imem->getBaseAddress() <= trans->addr
|
|
&& trans->addr < (imem->getBaseAddress() + imem->getLength())) {
|
|
|
|
imem->nb_transport(trans, cb);
|
|
unmapped = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (unmapped) {
|
if (memdev == 0) {
|
RISCV_error("[%" RV_PRI64 "d] Non-blocking request to unmapped address "
|
RISCV_error("[%" RV_PRI64 "d] Non-blocking request to unmapped address "
|
"%08" RV_PRI64 "x", iclk0_->getStepCounter(), trans->addr);
|
"%08" RV_PRI64 "x", iclk0_->getStepCounter(), trans->addr);
|
memset(trans->rpayload.b8, 0xFF, trans->xsize);
|
memset(trans->rpayload.b8, 0xFF, trans->xsize);
|
trans->response = MemResp_Error;
|
trans->response = MemResp_Error;
|
cb->nb_response(trans);
|
cb->nb_response(trans);
|
ret = TRANS_ERROR;
|
ret = TRANS_ERROR;
|
} else {
|
} else {
|
|
memdev->nb_transport(trans, cb);
|
RISCV_debug("Non-blocking request to [%08" RV_PRI64 "x]",
|
RISCV_debug("Non-blocking request to [%08" RV_PRI64 "x]",
|
trans->addr);
|
trans->addr);
|
}
|
}
|
|
|
// Update Bus utilization counters:
|
// Update Bus utilization counters:
|
|
if (idsu_) {
|
if (trans->action == MemAction_Read) {
|
if (trans->action == MemAction_Read) {
|
info_[trans->source_idx].r_cnt++;
|
idsu_->incrementRdAccess(trans->source_idx);
|
} else if (trans->action == MemAction_Write) {
|
} else if (trans->action == MemAction_Write) {
|
info_[trans->source_idx].w_cnt++;
|
idsu_->incrementWrAccess(trans->source_idx);
|
|
}
|
}
|
}
|
RISCV_mutex_unlock(&mutexNBAccess_);
|
RISCV_mutex_unlock(&mutexNBAccess_);
|
return ret;
|
return ret;
|
}
|
}
|
|
|
BusUtilType *Bus::bus_utilization() {
|
void Bus::getMapedDevice(Axi4TransactionType *trans,
|
return info_;
|
IMemoryOperation **pdev, uint32_t *sz) {
|
|
IMemoryOperation *imem;
|
|
uint64_t bar, barsz;
|
|
*pdev = 0;
|
|
*sz = 0;
|
|
for (unsigned i = 0; i < imap_.size(); i++) {
|
|
imem = static_cast<IMemoryOperation *>(imap_[i].to_iface());
|
|
bar = imem->getBaseAddress();
|
|
barsz = imem->getLength();
|
|
if (bar <= trans->addr && trans->addr < (bar + barsz)) {
|
|
if (!(*pdev) || imem->getPriority() > (*pdev)->getPriority()) {
|
|
*pdev = imem;
|
|
}
|
|
}
|
|
}
|
}
|
}
|
|
|
} // namespace debugger
|
} // namespace debugger
|
|
|
No newline at end of file
|
No newline at end of file
|