blob: e9f5c06a01248697e9035df98ab94ab94be205d3 [file]
// Copyright 2026 Google LLC
//
// Licensed 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
//
// https://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 "riscv/riscv_gdb_debug_info.h"
#include <string>
#include <string_view>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "mpact/sim/generic/type_helpers.h"
namespace {
std::string EscapeString(std::string_view str) {
std::string escaped_string;
escaped_string.reserve(str.size() * 2);
for (char c : str) {
if ((c == '$') || (c == '#') || (c == '*') || (c == '}')) {
escaped_string.push_back('}');
escaped_string.push_back(c ^ 0x20);
} else {
escaped_string.push_back(c);
}
}
return escaped_string;
}
} // namespace
namespace mpact::sim::riscv {
using ::mpact::sim::generic::operator*; // NOLINT
RiscVGdbDebugInfo* RiscVGdbDebugInfo::Instance(int gpr_width, int fp_width,
int vec_width) {
static absl::flat_hash_map<int, RiscVGdbDebugInfo*> instance_map;
// Check for valid widths.
if (gpr_width != 32 && gpr_width != 64) return nullptr;
if (fp_width != 0 && fp_width != 32 && fp_width != 64) return nullptr;
if (vec_width != 0 && vec_width != 128 && vec_width != 256 &&
vec_width != 512 && vec_width != 1024) {
return nullptr;
}
int key = gpr_width | (fp_width << 16) | (vec_width << 24);
auto it = instance_map.find(key);
if (it != instance_map.end()) {
return it->second;
}
RiscVGdbDebugInfo* instance =
new RiscVGdbDebugInfo(gpr_width, fp_width, vec_width);
instance_map[key] = instance;
return instance;
}
RiscVGdbDebugInfo::RiscVGdbDebugInfo(int gpr_width, int fp_width, int vec_width)
: gpr_width_(gpr_width), fp_width_(fp_width), vec_width_(vec_width) {
host_info_ = absl::StrFormat(
"triple:riscv%d-unknown-elf;"
"endian:little;"
"ptrsize:%d;"
"vendor:riscv;",
gpr_width_, gpr_width_ / 8);
// PC register.
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kGprPc, "pc");
// Integer registers.
for (int i = *RiscVGdbRegisterEnum::kGprX0;
i <= *RiscVGdbRegisterEnum::kGprX31; ++i) {
debug_register_map_.emplace(
i, absl::StrCat("x", i - *RiscVGdbRegisterEnum::kGprX0));
}
if (fp_width != 0) {
// Floating point registers.
for (int i = *RiscVGdbRegisterEnum::kFprFirst;
i <= *RiscVGdbRegisterEnum::kFprLast; ++i) {
debug_register_map_.emplace(
i, absl::StrCat("f", i - *RiscVGdbRegisterEnum::kFprFirst));
}
// CSRs.
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kFprFcsr, "fcsr");
}
if (vec_width != 0) {
// Vector control registers.
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVstart, "vstart");
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVxsat, "vxsat");
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVxrm, "vxrm");
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVcsr, "vcsr");
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVl, "vl");
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVtype, "vtype");
debug_register_map_.emplace(*RiscVGdbRegisterEnum::kVprVlenb, "vlenb");
}
// Construct the gdb target xml string.
gdb_target_xml_ = R"xml(<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<architecture>riscv</architecture>)xml";
absl::StrAppend(&gdb_target_xml_,
"\n <feature name=\"org.gnu.gdb.riscv.cpu\">\n");
// GPR registers.
int regnum = 0;
for (int i = 0; i < 32; ++i) {
absl::StrAppend(
&gdb_target_xml_,
absl::StrFormat(" <reg name=\"x%d\" bitsize=\"%d\" regnum=\"%d\" "
"type=\"uint%d\" group=\"general\"/>\n",
i, gpr_width_, regnum++, gpr_width_));
}
absl::StrAppend(
&gdb_target_xml_,
absl::StrFormat(" <reg name=\"pc\" bitsize=\"%d\" regnum=\"%d\" "
"type=\"code_ptr\" group=\"general\"/>\n",
gpr_width_, regnum++));
absl::StrAppend(&gdb_target_xml_, " </feature>\n");
// FP registers.
if (fp_width != 0) {
absl::StrAppend(&gdb_target_xml_,
" <feature name=\"org.gnu.gdb.riscv.fpu\">\n");
std::string fp_type = fp_width == 64 ? "ieee_double" : "ieee_float";
for (int i = 0; i < 32; ++i) {
absl::StrAppend(
&gdb_target_xml_,
absl::StrFormat(" <reg name=\"f%d\" bitsize=\"%d\" "
"regnum=\"%d\" type=\"%s\" group=\"float\"/>\n",
i, fp_width_, regnum++, fp_type));
}
absl::StrAppend(
&gdb_target_xml_,
absl::StrFormat(" <reg name=\"fcsr\" bitsize=\"%d\" regnum=\"%d\" "
"type=\"uint32\" group=\"float\"/>\n",
32, regnum++));
absl::StrAppend(&gdb_target_xml_, " </feature>\n");
}
// Vector registers.
if (vec_width != 0) {
absl::StrAppend(&gdb_target_xml_,
" <feature name=\"org.gnu.gdb.riscv.vector\">\n");
// Add vector data type.
absl::StrAppend(
&gdb_target_xml_,
absl::StrFormat(
" <vector id=\"v%d\" type=\"uint8\" count=\"%d\"/>\n",
vec_width_, vec_width_ / 8));
for (int i = 0; i < 32; ++i) {
absl::StrAppend(&gdb_target_xml_,
absl::StrFormat(" <reg name=\"v%d\" bitsize=\"%d\" "
"regnum=\"%d\" type=\"v%d\" "
"group=\"vector\"/>\n",
i, vec_width_, regnum++, vec_width_));
}
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vstart\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vxsat\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vxrm\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vcsr\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vl\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vtype\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_,
" <reg name=\"vlenb\" bitsize=\"32\" type=\"uint32\" "
"group=\"vector\"/>\n");
absl::StrAppend(&gdb_target_xml_, " </feature>\n");
}
absl::StrAppend(&gdb_target_xml_, "</target>\n");
// Escape the string for GDB
gdb_target_xml_ = EscapeString(gdb_target_xml_);
}
} // namespace mpact::sim::riscv