/**
|
/**
|
* @file
|
* @file
|
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
* @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* @author Sergey Khabarov - sergeykhbr@gmail.com
|
* @brief ROM functional model implementation.
|
* @brief ROM functional model implementation.
|
*/
|
*/
|
|
|
#include "api_core.h"
|
#include "api_core.h"
|
#include "memsim.h"
|
#include "memsim.h"
|
#include <iostream>
|
#include <iostream>
|
#include <string.h>
|
#include <string.h>
|
|
|
namespace debugger {
|
namespace debugger {
|
|
|
/** Class registration in the Core */
|
/** Class registration in the Core */
|
REGISTER_CLASS(MemorySim)
|
REGISTER_CLASS(MemorySim)
|
|
|
MemorySim::MemorySim(const char *name) : IService(name) {
|
MemorySim::MemorySim(const char *name) : IService(name) {
|
registerInterface(static_cast<IMemoryOperation *>(this));
|
registerInterface(static_cast<IMemoryOperation *>(this));
|
registerAttribute("InitFile", &initFile_);
|
registerAttribute("InitFile", &initFile_);
|
registerAttribute("ReadOnly", &readOnly_);
|
registerAttribute("ReadOnly", &readOnly_);
|
registerAttribute("BaseAddress", &baseAddress_);
|
registerAttribute("BinaryFile", &binaryFile_);
|
registerAttribute("Length", &length_);
|
|
|
|
initFile_.make_string("");
|
initFile_.make_string("");
|
readOnly_.make_boolean(false);
|
readOnly_.make_boolean(false);
|
baseAddress_.make_uint64(0);
|
binaryFile_.make_boolean(false);
|
length_.make_uint64(0);
|
|
mem_ = NULL;
|
mem_ = NULL;
|
}
|
}
|
|
|
MemorySim::~MemorySim() {
|
MemorySim::~MemorySim() {
|
if (mem_) {
|
if (mem_) {
|
delete mem_;
|
delete mem_;
|
}
|
}
|
}
|
}
|
|
|
void MemorySim::postinitService() {
|
void MemorySim::postinitService() {
|
// Get global settings:
|
// Get global settings:
|
const AttributeType *glb = RISCV_get_global_settings();
|
const AttributeType *glb = RISCV_get_global_settings();
|
if ((*glb)["SimEnable"].to_bool() == false) {
|
if ((*glb)["SimEnable"].to_bool() == false) {
|
return;
|
return;
|
}
|
}
|
|
|
mem_ = new uint8_t[static_cast<unsigned>(length_.to_uint64())];
|
mem_ = new uint8_t[static_cast<unsigned>(length_.to_uint64())];
|
if (initFile_.size() == 0) {
|
if (initFile_.size() == 0) {
|
return;
|
return;
|
}
|
}
|
|
|
std::string filename(initFile_.to_string());
|
std::string filename(initFile_.to_string());
|
if (strstr(initFile_.to_string(), "..") != NULL ||
|
if (strstr(initFile_.to_string(), "..") != NULL ||
|
strstr(initFile_.to_string(), "/") == NULL) {
|
strstr(initFile_.to_string(), "/") == NULL) {
|
char path[1024];
|
char path[1024];
|
RISCV_get_core_folder(path, sizeof(path));
|
RISCV_get_core_folder(path, sizeof(path));
|
std::string spath(path);
|
std::string spath(path);
|
filename = spath + std::string(initFile_.to_string());
|
filename = spath + std::string(initFile_.to_string());
|
}
|
}
|
|
|
FILE *fp = fopen(initFile_.to_string(), "r");
|
FILE *fp = fopen(initFile_.to_string(), "r");
|
if (fp == NULL) {
|
if (fp == NULL) {
|
for (uint64_t i = 0; i < length_.to_uint64()/4; i++) {
|
for (uint64_t i = 0; i < length_.to_uint64()/4; i++) {
|
// NOP isntruction
|
// NOP isntruction
|
reinterpret_cast<uint32_t *>(mem_)[i] = 0x00000013; // intialize by NOPs
|
reinterpret_cast<uint32_t *>(mem_)[i] = 0x00000013; // intialize by NOPs
|
}
|
}
|
RISCV_error("Can't open '%s' file", initFile_.to_string());
|
RISCV_error("Can't open '%s' file", initFile_.to_string());
|
return;
|
return;
|
}
|
}
|
|
|
|
if (binaryFile_.to_bool()) {
|
|
fseek(fp, 0, SEEK_END);
|
|
uint64_t fsz = ftell(fp);
|
|
if (fsz > length_.to_uint64()) {
|
|
fsz = length_.to_uint64();
|
|
}
|
|
fseek(fp, 0, SEEK_SET);
|
|
fread(mem_, 1, static_cast<size_t>(fsz), fp);
|
|
} else {
|
bool bhalf = false;
|
bool bhalf = false;
|
int rd_symb;
|
int rd_symb;
|
uint8_t symb;
|
uint8_t symb;
|
int linecnt = 0;
|
int linecnt = 0;
|
int symbinline = SYMB_IN_LINE - 1;
|
int symbinline = SYMB_IN_LINE - 1;
|
while (!feof(fp)) {
|
while (!feof(fp)) {
|
rd_symb = fgetc(fp);
|
rd_symb = fgetc(fp);
|
if (!chishex(rd_symb))
|
if (!chishex(rd_symb))
|
continue;
|
continue;
|
|
|
if (!bhalf) {
|
if (!bhalf) {
|
bhalf = true;
|
bhalf = true;
|
symb = chtohex(rd_symb) << 4;
|
symb = chtohex(rd_symb) << 4;
|
continue;
|
continue;
|
}
|
}
|
|
|
bhalf = false;
|
bhalf = false;
|
symb |= chtohex(rd_symb) & 0xf;
|
symb |= chtohex(rd_symb) & 0xf;
|
|
|
if ((SYMB_IN_LINE * linecnt + symbinline) >=
|
if ((SYMB_IN_LINE * linecnt + symbinline) >=
|
static_cast<int>(length_.to_uint64())) {
|
static_cast<int>(length_.to_uint64())) {
|
RISCV_error("HEX file tries to write out "
|
RISCV_error("HEX file tries to write out "
|
"of allocated array\n", NULL);
|
"of allocated array\n", NULL);
|
break;
|
break;
|
}
|
}
|
|
|
mem_[SYMB_IN_LINE * linecnt + symbinline] = symb;
|
mem_[SYMB_IN_LINE * linecnt + symbinline] = symb;
|
if (--symbinline < 0) {
|
if (--symbinline < 0) {
|
linecnt++;
|
linecnt++;
|
symbinline = SYMB_IN_LINE - 1;
|
symbinline = SYMB_IN_LINE - 1;
|
}
|
}
|
}
|
}
|
|
}
|
fclose(fp);
|
fclose(fp);
|
}
|
}
|
|
|
void MemorySim::b_transport(Axi4TransactionType *trans) {
|
ETransStatus MemorySim::b_transport(Axi4TransactionType *trans) {
|
uint64_t mask = (length_.to_uint64() - 1);
|
uint64_t off = (trans->addr - getBaseAddress()) % length_.to_int();
|
uint64_t off = (trans->addr - getBaseAddress()) & mask;
|
|
trans->response = MemResp_Valid;
|
trans->response = MemResp_Valid;
|
if (trans->action == MemAction_Write) {
|
if (trans->action == MemAction_Write) {
|
if (readOnly_.to_bool()) {
|
if (readOnly_.to_bool()) {
|
RISCV_error("Write to READ ONLY memory", NULL);
|
RISCV_error("Write to READ ONLY memory", NULL);
|
trans->response = MemResp_Error;
|
trans->response = MemResp_Error;
|
} else {
|
} else {
|
for (uint64_t i = 0; i < trans->xsize; i++) {
|
for (uint64_t i = 0; i < trans->xsize; i++) {
|
if (((trans->wstrb >> i) & 0x1) == 0) {
|
if (((trans->wstrb >> i) & 0x1) == 0) {
|
continue;
|
continue;
|
}
|
}
|
mem_[off + i] = trans->wpayload.b8[i];
|
mem_[off + i] = trans->wpayload.b8[i];
|
}
|
}
|
}
|
}
|
} else {
|
} else {
|
memcpy(trans->rpayload.b8, &mem_[off], trans->xsize);
|
memcpy(trans->rpayload.b8, &mem_[off], trans->xsize);
|
}
|
}
|
|
|
const char *rw_str[2] = {"=>", "<="};
|
const char *rw_str[2] = {"=>", "<="};
|
uint32_t *pdata[2] = {trans->rpayload.b32, trans->wpayload.b32};
|
uint32_t *pdata[2] = {trans->rpayload.b32, trans->wpayload.b32};
|
RISCV_debug("[%08" RV_PRI64 "x] %s [%08x %08x]",
|
RISCV_debug("[%08" RV_PRI64 "x] %s [%08x %08x]",
|
trans->addr,
|
trans->addr,
|
rw_str[trans->action],
|
rw_str[trans->action],
|
pdata[trans->action][1], pdata[trans->action][0]);
|
pdata[trans->action][1], pdata[trans->action][0]);
|
|
return TRANS_OK;
|
}
|
}
|
|
|
bool MemorySim::chishex(int s) {
|
bool MemorySim::chishex(int s) {
|
bool ret = false;
|
bool ret = false;
|
if (s >= '0' && s <= '9') {
|
if (s >= '0' && s <= '9') {
|
ret = true;
|
ret = true;
|
} else if (s >= 'A' && s <= 'F') {
|
} else if (s >= 'A' && s <= 'F') {
|
ret = true;
|
ret = true;
|
} else if (s >= 'a' && s <= 'f') {
|
} else if (s >= 'a' && s <= 'f') {
|
ret = true;
|
ret = true;
|
}
|
}
|
return ret;
|
return ret;
|
}
|
}
|
|
|
uint8_t MemorySim::chtohex(int s) {
|
uint8_t MemorySim::chtohex(int s) {
|
if (s >= '0' && s <= '9') {
|
if (s >= '0' && s <= '9') {
|
s -= '0';
|
s -= '0';
|
} else if (s >= 'A' && s <= 'F') {
|
} else if (s >= 'A' && s <= 'F') {
|
s = s - 'A' + 10;
|
s = s - 'A' + 10;
|
} else if (s >= 'a' && s <= 'f') {
|
} else if (s >= 'a' && s <= 'f') {
|
s = s - 'a' + 10;
|
s = s - 'a' + 10;
|
}
|
}
|
return static_cast<uint8_t>(s);
|
return static_cast<uint8_t>(s);
|
}
|
}
|
|
|
} // namespace debugger
|
} // namespace debugger
|
|
|
|
|