1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 using ELFSharp.ELF; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Utilities; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Timers; 15 16 namespace Antmicro.Renode.Peripherals.CPU 17 { 18 public partial class VexRiscv : RiscV32 19 { VexRiscv(IMachine machine, uint hartId = 0, IRiscVTimeProvider timeProvider = null, [NameAlias(R)] PrivilegedArchitecture privilegedArchitecture = PrivilegedArchitecture.Priv1_10, string cpuType = R, bool builtInIrqController = true)20 public VexRiscv(IMachine machine, uint hartId = 0, IRiscVTimeProvider timeProvider = null, [NameAlias("privilegeArchitecture")] PrivilegedArchitecture privilegedArchitecture = PrivilegedArchitecture.Priv1_10, string cpuType = "rv32im_Zicsr_Zifencei", bool builtInIrqController = true) : base(machine, cpuType, timeProvider, hartId, privilegedArchitecture, Endianess.LittleEndian) 21 { 22 this.builtInIrqController = builtInIrqController; 23 if(builtInIrqController) 24 { 25 RegisterCustomCSRs(); 26 } 27 28 RegisterCustomInstructions(); 29 } 30 31 // GPIOs for the original (non-standard) VexRiscv configuration 32 // are divided into the following sections: 33 // 0 - 31 : machine level external interrupts 34 // 100 : machine level timer interrupt 35 // 101 : machine level software interrupt 36 // 1000 - 1031 : supervisor level external interrupts OnGPIO(int number, bool value)37 public override void OnGPIO(int number, bool value) 38 { 39 lock(locker) 40 { 41 this.Log(LogLevel.Noisy, "GPIO #{0} set to: {1}", number, value); 42 if(!builtInIrqController) 43 { 44 base.OnGPIO(number, value); 45 } 46 else 47 { 48 if(number == MachineTimerInterruptCustomNumber) 49 { 50 base.OnGPIO((int)IrqType.MachineTimerInterrupt, value); 51 } 52 else if (number == MachineSoftwareInterruptCustomNumber) 53 { 54 base.OnGPIO((int)IrqType.MachineSoftwareInterrupt, value); 55 } 56 else if(number >= SupervisorExternalInterruptsOffset) 57 { 58 BitHelper.SetBit(ref supervisorInterrupts.Pending, (byte)(number - SupervisorExternalInterruptsOffset), value); 59 Update(); 60 } 61 else // machine external 62 { 63 BitHelper.SetBit(ref machineInterrupts.Pending, (byte)number, value); 64 Update(); 65 } 66 } 67 } 68 } 69 Reset()70 public override void Reset() 71 { 72 base.Reset(); 73 dCacheInfo = 0; 74 75 if(builtInIrqController) 76 { 77 machineInterrupts = new Interrupts(); 78 supervisorInterrupts = new Interrupts(); 79 } 80 } 81 82 // this is a helper method to allow 83 // setting irq mask from the monitor SetMachineIrqMask(uint mask)84 public void SetMachineIrqMask(uint mask) 85 { 86 machineInterrupts.Mask = mask; 87 } 88 89 // this is a helper method to allow 90 // setting irq mask from the monitor SetSupervisorIrqMask(uint mask)91 public void SetSupervisorIrqMask(uint mask) 92 { 93 supervisorInterrupts.Mask = mask; 94 } 95 Update()96 private void Update() 97 { 98 base.OnGPIO((int)IrqType.MachineExternalInterrupt, machineInterrupts.Any); 99 base.OnGPIO((int)IrqType.SupervisorExternalInterrupt, supervisorInterrupts.Any); 100 } 101 HandleFlushDataCacheInstruction(UInt64 opcode)102 private void HandleFlushDataCacheInstruction(UInt64 opcode) 103 { 104 // intentionally do nothing 105 // there is no data cache in Renode anyway 106 } 107 RegisterCustomInstructions()108 private void RegisterCustomInstructions() 109 { 110 InstallCustomInstruction(pattern: "00000000000000000101000000001111", handler: HandleFlushDataCacheInstruction); 111 } 112 RegisterCustomCSRs()113 private void RegisterCustomCSRs() 114 { 115 // validate only privilege level when accessing CSRs 116 // do not validate rw bit as VexRiscv custom CSRs do not follow the standard 117 CSRValidation = CSRValidationLevel.PrivilegeLevel; 118 119 RegisterCSR((ulong)CSRs.MachineIrqMask, () => (ulong)machineInterrupts.Mask, value => 120 { 121 lock(locker) 122 { 123 machineInterrupts.Mask = (uint)value; 124 this.Log(LogLevel.Noisy, "Machine IRQ mask set to 0x{0:X}", machineInterrupts.Mask); 125 Update(); 126 } 127 }); 128 RegisterCSR((ulong)CSRs.MachineIrqPending, () => (ulong)machineInterrupts.Pending, value => 129 { 130 lock(locker) 131 { 132 machineInterrupts.Pending = (uint)value; 133 this.Log(LogLevel.Noisy, "Machine IRQ pending set to 0x{0:X}", machineInterrupts.Pending); 134 Update(); 135 } 136 }); 137 RegisterCSR((ulong)CSRs.SupervisorIrqMask, () => (ulong)supervisorInterrupts.Mask, value => 138 { 139 lock(locker) 140 { 141 supervisorInterrupts.Mask = (uint)value; 142 this.Log(LogLevel.Noisy, "Supervisor IRQ mask set to 0x{0:X}", supervisorInterrupts.Mask); 143 Update(); 144 } 145 }); 146 RegisterCSR((ulong)CSRs.SupervisorIrqPending, () => (ulong)supervisorInterrupts.Pending, value => 147 { 148 lock(locker) 149 { 150 supervisorInterrupts.Pending = (uint)value; 151 this.Log(LogLevel.Noisy, "Supervisor IRQ pending set to 0x{0:X}", supervisorInterrupts.Pending); 152 Update(); 153 } 154 }); 155 RegisterCSR((ulong)CSRs.DCacheInfo, () => (ulong)dCacheInfo, value => dCacheInfo = (uint)value); 156 } 157 158 private Interrupts machineInterrupts; 159 private Interrupts supervisorInterrupts; 160 private uint dCacheInfo; 161 162 private readonly bool builtInIrqController; 163 private readonly object locker = new object(); 164 165 // this is non-standard number for Machine Timer Interrupt, 166 // but it's moved to 100 to avoid conflicts with VexRiscv 167 // built-in interrupt manager that is mapped to IRQs 0-31 168 private const int MachineTimerInterruptCustomNumber = 100; 169 170 // this is non-standard number for Machine Software Interrupt, 171 // but it's moved to 101 to avoid conflicts with VexRiscv 172 // built-in interrupt manager that is mapped to IRQs 0-31 173 private const int MachineSoftwareInterruptCustomNumber = 101; 174 175 private const int SupervisorExternalInterruptsOffset = 1000; 176 177 private struct Interrupts 178 { 179 public uint Mask; 180 public uint Pending; 181 182 public bool Any => (Mask & Pending) != 0; 183 } 184 185 private enum CSRs 186 { 187 MachineIrqMask = 0xBC0, 188 MachineIrqPending = 0xFC0, 189 SupervisorIrqMask = 0x9C0, 190 SupervisorIrqPending = 0xDC0, 191 DCacheInfo = 0xCC0 192 } 193 } 194 } 195