blob: 1d273f604e06d724baa87ff676feae9d7c370701 [file] [log] [blame]
//
// Copyright (c) 2010-2024 Antmicro
//
// This file is licensed under the MIT License.
// Full license text is available in 'licenses/MIT.txt'.
//
//
// Copyright (c) 2024 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
//
// This file specializes the MpactCPU class to add custom interfaces and
// properties required for the mpact_cheriot simulator.
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Antmicro.Renode.Core;
using Antmicro.Renode.Debugging;
using Antmicro.Renode.Exceptions;
using Antmicro.Renode.Hooks;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.CPU;
using Antmicro.Renode.Peripherals.Timers;
using Antmicro.Renode.Peripherals.CPU.Disassembler;
using Antmicro.Renode.Peripherals.CPU.Registers;
using Antmicro.Renode.Utilities;
using Antmicro.Renode.Time;
using Antmicro.Renode.Utilities.Binding;
using Antmicro.Renode.Peripherals.MpactCPU;
using ELFSharp.ELF;
using ELFSharp.UImage;
namespace Antmicro.Renode.Peripherals.MpactCPU
{
// The MpactRiscvCPU class. This class derives from BaseCPU, which implements
// a CPU in ReNode. It is the interface between ReNode and the mpact_riscv32/64
// simulator libraries.
public class MpactRiscVCPU : MpactBaseCPU, ICluster<MpactRiscVCPU>,
ICpuSupportingGdb {
public MpactRiscVCPU(uint id, UInt64 memoryBase, UInt64 memorySize,
string cpuType, IMachine machine,
Endianess endianness,
CpuBitness bitness = CpuBitness.Bits32)
: base(id, memoryBase, memorySize, cpuType, machine, endianness,
bitness) {
Clustered = new MpactRiscVCPU[] { this };
}
~MpactRiscVCPU() {
}
public override string Architecture { get { return "MpactRiscV";} }
public override void SetMpactConfig(List<string> config_names,
List<string> config_values) {
base.SetMpactConfig(config_names, config_values);
if (inst_profile) {
config_names.Add("instProfile");
config_values.Add("0x1");
}
if (mem_profile) {
config_names.Add("memProfile");
config_values.Add("0x1");
}
// Stack
if (stack_size_set) {
config_names.Add("stackSize");
config_values.Add(stack_size.ToString("X"));
}
if (stack_end_set) {
config_names.Add("stackEnd");
config_values.Add(stack_end.ToString("X"));
}
if (icache_config != "") {
config_names.Add("iCache");
config_values.Add(icache_config);
}
if (dcache_config != "") {
config_names.Add("dCache");
config_values.Add(dcache_config);
}
}
public bool InstProfile {
get => inst_profile;
set => inst_profile = value;
}
public bool MemProfile {
get => mem_profile;
set => mem_profile = value;
}
public ulong StackSize {
get => stack_size;
set {
stack_size = value;
stack_size_set = true;
}
}
public ulong StackEnd {
get => stack_end;
set {
stack_end = value;
stack_end_set = true;
}
}
public string ICache {
get => icache_config;
set => icache_config = value;
}
public string DCache {
get => dcache_config;
set => dcache_config = value;
}
// ICPUWithHooks methods.
public void AddHookAtInterruptBegin(Action<ulong> hook) {
throw new RecoverableException(
"Interrupt hooks not currently supported");
}
public void AddHookAtInterruptEnd(Action<ulong> hook) {
throw new RecoverableException(
"Interrupt hooks not currently supported");
}
public void AddHookAtWfiStateChange(Action<bool> hook) {
throw new RecoverableException(
"Wfi state change hook not currently supported");
}
public void AddHook(ulong addr, Action<ICpuSupportingGdb, ulong> hook) {
throw new RecoverableException("Hooks not currently supported");
}
public void RemoveHook(ulong addr, Action<ICpuSupportingGdb, ulong> hook) {
/* empty */
}
public void RemoveHooksAt(ulong addr) { /* empty */ }
public void RemoveAllHooks() { /* empty */ }
// ICluster methods.
public new IEnumerable<ICluster<MpactRiscVCPU>> Clusters {get; } = new List<ICluster<MpactRiscVCPU>>(0);
public new IEnumerable<MpactRiscVCPU> Clustered {get; }
// ICPUSupportingGdb methods.
public void EnterSingleStepModeSafely(HaltArguments args) {
// this method should only be called from CPU thread,
// but we should check it anyway
CheckCpuThreadId();
ExecutionMode = ExecutionMode.SingleStep;
UpdateHaltedState();
InvokeHalted(args);
}
public string GDBArchitecture { get { return "riscv:riscv"; } }
public List<GDBFeatureDescriptor> GDBFeatures {
get {
if (gdbFeatures.Any()) return gdbFeatures;
// Populate the register map if it hasn't been done yet.
if (registerNamesMap.Count == 0) {
GetMpactRegisters();
}
var cpuGroup = new GDBFeatureDescriptor("org.gnu.gdb.riscv.cpu");
var intType = $"uint32";
var c0_index = registerNamesMap["c0"];
for (var i = 0u; i < 16; ++i) {
cpuGroup.Registers.Add(
new GDBRegisterDescriptor((uint)c0_index + i, 32u,
$"c{i}", intType, "general"));
}
var pcc_index = registerNamesMap["pcc"];
cpuGroup.Registers.Add(
new GDBRegisterDescriptor((uint)pcc_index, 32u, "pcc",
"code_ptr", "general"));
gdbFeatures.Add(cpuGroup);
return gdbFeatures;
}
}
// End of ICpuSupportingGdb methods.
private bool inst_profile = false;
private bool mem_profile = false;
private ulong stack_size;
private bool stack_size_set = false;
private ulong stack_end;
private bool stack_end_set = false;
private string icache_config = "";
private string dcache_config = "";
private List<GDBFeatureDescriptor>
gdbFeatures = new List<GDBFeatureDescriptor>();
} // class MpactRiscVCPU
} // namespace Antmicro.Renode.Peripherals.MpactCPU