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