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 Antmicro.Renode.Core;
8 using Antmicro.Renode.Logging;
9 using Antmicro.Renode.Peripherals.Timers;
10 using Antmicro.Renode.Utilities;
11 using Endianess = ELFSharp.ELF.Endianess;
12 
13 namespace Antmicro.Renode.Peripherals.CPU
14 {
15     public class CV32E40P : RiscV32
16     {
CV32E40P(IMachine machine, IRiscVTimeProvider timeProvider = null, uint hartId = 0, [NameAlias(R)] PrivilegedArchitecture privilegedArchitecture = PrivilegedArchitecture.Priv1_11, Endianess endianness = Endianess.LittleEndian, string cpuType = R)17         public CV32E40P(IMachine machine, IRiscVTimeProvider timeProvider = null, uint hartId = 0, [NameAlias("privilegeArchitecture")] PrivilegedArchitecture privilegedArchitecture = PrivilegedArchitecture.Priv1_11, Endianess endianness = Endianess.LittleEndian, string cpuType = "rv32imfc_zicsr_zifencei")
18             : base(machine, cpuType, timeProvider, hartId, privilegedArchitecture, endianness, allowUnalignedAccesses : true)
19         {
20             // enable all interrupt sources
21             MIE = 0xffffffff;
22 
23             RegisterCSR((ulong)CustomCSR.PerformanceCounterMode, () => LogUnhandledCSRRead("PerformanceCounterMode"), val => LogUnhandledCSRWrite("PerformanceCounterMode", val));
24             RegisterCSR((ulong)CustomCSR.StackCheckEnable      , () => LogUnhandledCSRRead("StackCheckEnable")      , val => LogUnhandledCSRWrite("StackCheckEnable", val));
25             RegisterCSR((ulong)CustomCSR.StackBase             , () => LogUnhandledCSRRead("StackBase")             , val => LogUnhandledCSRWrite("StackBase", val));
26             RegisterCSR((ulong)CustomCSR.StackEnd              , () => LogUnhandledCSRRead("StackEnd")              , val => LogUnhandledCSRWrite("StackEnd", val));
27             RegisterCSR((ulong)CustomCSR.HardwareLoop0Start    , () => LogUnhandledCSRRead("HardwareLoop0Start")    , val => LogUnhandledCSRWrite("HardwareLoop0Start", val));
28             RegisterCSR((ulong)CustomCSR.HardwareLoop0End      , () => LogUnhandledCSRRead("HardwareLoop0End")      , val => LogUnhandledCSRWrite("HardwareLoop0End", val));
29             RegisterCSR((ulong)CustomCSR.HardwareLoop0Counter  , () => LogUnhandledCSRRead("HardwareLoop0Counter")  , val => LogUnhandledCSRWrite("HardwareLoop0Counter", val));
30             RegisterCSR((ulong)CustomCSR.HardwareLoop1Start    , () => LogUnhandledCSRRead("HardwareLoop1Start")    , val => LogUnhandledCSRWrite("HardwareLoop1Start", val));
31             RegisterCSR((ulong)CustomCSR.HardwareLoop1End      , () => LogUnhandledCSRRead("HardwareLoop1End")      , val => LogUnhandledCSRWrite("HardwareLoop1End", val));
32             RegisterCSR((ulong)CustomCSR.HardwareLoop1Counter  , () => LogUnhandledCSRRead("HardwareLoop1Counter")  , val => LogUnhandledCSRWrite("HardwareLoop1Counter", val));
33 
34             InstallCustomInstruction(pattern: "FFFFFFFFFFFFBBBBB000DDDDD0001011", handler: opcode => LoadRegisterImmediate(opcode, Width.Byte, BitExtension.Sign, "p.lb rD, Imm(rs1!)"));
35             InstallCustomInstruction(pattern: "FFFFFFFFFFFFBBBBB100DDDDD0001011", handler: opcode => LoadRegisterImmediate(opcode, Width.Byte, BitExtension.Zero, "p.lbu rD, Imm(rs1!)"));
36             InstallCustomInstruction(pattern: "FFFFFFFFFFFFBBBBB001DDDDD0001011", handler: opcode => LoadRegisterImmediate(opcode, Width.HalfWord, BitExtension.Sign, "p.lh rD, Imm(rs1!)"));
37             InstallCustomInstruction(pattern: "FFFFFFFFFFFFBBBBB101DDDDD0001011", handler: opcode => LoadRegisterImmediate(opcode, Width.HalfWord, BitExtension.Zero, "p.lhu rD, Imm(rs1!)"));
38             InstallCustomInstruction(pattern: "FFFFFFFFFFFFBBBBB010DDDDD0001011", handler: opcode => LoadRegisterImmediate(opcode, Width.Word, BitExtension.Zero, "p.lw rD, Imm(rs1!)"));
39             InstallCustomInstruction(pattern: "0000000FFFFFBBBBB111DDDDD0001011", handler: opcode => LoadRegisterRegister(opcode, Width.Byte, BitExtension.Sign, postIncrement: true, log: "p.lb rD, rs2(rs1!)"));
40             InstallCustomInstruction(pattern: "0100000FFFFFBBBBB111DDDDD0001011", handler: opcode => LoadRegisterRegister(opcode, Width.Byte, BitExtension.Zero, postIncrement: true, log: "p.lbu rD, rs2(rs1!)"));
41             InstallCustomInstruction(pattern: "0001000FFFFFBBBBB111DDDDD0001011", handler: opcode => LoadRegisterRegister(opcode, Width.HalfWord, BitExtension.Sign, postIncrement: true, log: "p.lh rD, rs2(rs1!)"));
42             InstallCustomInstruction(pattern: "0101000FFFFFBBBBB111DDDDD0001011", handler: opcode => LoadRegisterRegister(opcode, Width.HalfWord, BitExtension.Zero, postIncrement: true, log: "p.lhu rD, rs2(rs1!)"));
43             InstallCustomInstruction(pattern: "0010000FFFFFBBBBB111DDDDD0001011", handler: opcode => LoadRegisterRegister(opcode, Width.Word, BitExtension.Zero, postIncrement: true, log: "p.lw rD, rs2(rs1!)"));
44             InstallCustomInstruction(pattern: "0000000FFFFFBBBBB111DDDDD0000011", handler: opcode => LoadRegisterRegister(opcode, Width.Byte, BitExtension.Sign, "p.lb rD, rs2(rs1)"));
45             InstallCustomInstruction(pattern: "0100000FFFFFBBBBB111DDDDD0000011", handler: opcode => LoadRegisterRegister(opcode, Width.Byte, BitExtension.Zero, "p.lbu rD, rs2(rs1)"));
46             InstallCustomInstruction(pattern: "0001000FFFFFBBBBB111DDDDD0000011", handler: opcode => LoadRegisterRegister(opcode, Width.HalfWord, BitExtension.Sign, "p.lh rD, rs2(rs1)"));
47             InstallCustomInstruction(pattern: "0101000FFFFFBBBBB111DDDDD0000011", handler: opcode => LoadRegisterRegister(opcode, Width.HalfWord, BitExtension.Zero, "p.lhu rD, rs2(rs1)"));
48             InstallCustomInstruction(pattern: "0010000FFFFFBBBBB111DDDDD0000011", handler: opcode => LoadRegisterRegister(opcode, Width.Word, BitExtension.Zero, "p.lw rD, rs2(rs1)"));
49             InstallCustomInstruction(pattern: "FFFFFFFSSSSSBBBBB000FFFFF0101011", handler: opcode => StoreRegisterImmediate(opcode, Width.Byte, "p.sb rs2, Imm(rs1!)"));
50             InstallCustomInstruction(pattern: "FFFFFFFSSSSSBBBBB001FFFFF0101011", handler: opcode => StoreRegisterImmediate(opcode, Width.HalfWord, "p.sh rs2, Imm(rs1!)"));
51             InstallCustomInstruction(pattern: "FFFFFFFSSSSSBBBBB010FFFFF0101011", handler: opcode => StoreRegisterImmediate(opcode, Width.Word, "p.sw rs2, Imm(rs1!)"));
52             InstallCustomInstruction(pattern: "0000000SSSSSBBBBB100FFFFF0101011", handler: opcode => StoreRegisterRegister(opcode, Width.Byte, postIncrement: true, log: "p.sb rs2, rs3(rs1!)"));
53             InstallCustomInstruction(pattern: "0000000SSSSSBBBBB101FFFFF0101011", handler: opcode => StoreRegisterRegister(opcode, Width.HalfWord, postIncrement: true, log: "p.sh rs2, rs3(rs1!)"));
54             InstallCustomInstruction(pattern: "0000000SSSSSBBBBB110FFFFF0101011", handler: opcode => StoreRegisterRegister(opcode, Width.Word, postIncrement: true, log: "p.sw rs2, rs3(rs1!)"));
55             InstallCustomInstruction(pattern: "0000000SSSSSBBBBB100FFFFF0100011", handler: opcode => StoreRegisterRegister(opcode, Width.Byte, "p.sb rs2, rs3(rs1)"));
56             InstallCustomInstruction(pattern: "0000000SSSSSBBBBB101FFFFF0100011", handler: opcode => StoreRegisterRegister(opcode, Width.HalfWord, "p.sh rs2, rs3(rs1)"));
57             InstallCustomInstruction(pattern: "0000000SSSSSBBBBB110FFFFF0100011", handler: opcode => StoreRegisterRegister(opcode, Width.Word, "p.sw rs2, rs3(rs1)"));
58             InstallCustomInstruction(pattern: "0000010RRRRRSSSSS100DDDDD0110011", handler: opcode => CompareRegisters(opcode, ComparisonType.Min, Sign.Signed, "p.min rD, rs1, rs2"));
59             InstallCustomInstruction(pattern: "0000010RRRRRSSSSS101DDDDD0110011", handler: opcode => CompareRegisters(opcode, ComparisonType.Min, Sign.Unsigned, "p.minu rD, rs1, rs2"));
60             InstallCustomInstruction(pattern: "0000010RRRRRSSSSS110DDDDD0110011", handler: opcode => CompareRegisters(opcode, ComparisonType.Max, Sign.Signed, "p.max rD, rs1, rs2"));
61             InstallCustomInstruction(pattern: "0000010RRRRRSSSSS111DDDDD0110011", handler: opcode => CompareRegisters(opcode, ComparisonType.Max, Sign.Unsigned, "p.maxu rD, rs1, rs2"));
62             InstallCustomInstruction(pattern: "11LLLLLLLLLLSSSSS000DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Extract, Width.Word, Sign.Signed, "p.extract rD, rs1, Is3, Is2"));
63             InstallCustomInstruction(pattern: "11LLLLLLLLLLSSSSS001DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Extract, Width.Word, Sign.Unsigned, "p.extractu rD, rs1, Is3, Is2"));
64             InstallCustomInstruction(pattern: "1000000LLLLLSSSSS000DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Register, Operation.Extract, Width.Word, Sign.Signed, "p.extractr rD, rs1, rs2"));
65             InstallCustomInstruction(pattern: "1000000LLLLLSSSSS001DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Register, Operation.Extract, Width.Word, Sign.Unsigned, "p.extractur rD, rs1, rs2"));
66             InstallCustomInstruction(pattern: "000100000000SSSSS100DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Extract, Width.HalfWord, Sign.Signed, "p.exths rD, rs1"));
67             InstallCustomInstruction(pattern: "000100000000SSSSS101DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Extract, Width.HalfWord, Sign.Unsigned, "p.exthz rD, rs1"));
68             InstallCustomInstruction(pattern: "000100000000SSSSS110DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Extract, Width.Byte, Sign.Signed, "p.extbs rD, rs1"));
69             InstallCustomInstruction(pattern: "000100000000SSSSS111DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Extract, Width.Byte, Sign.Unsigned, "p.extbz rD, rs1"));
70             InstallCustomInstruction(pattern: "11LLLLLLLLLLSSSSS010DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Insert, Width.Word, Sign.Unsigned, "p.insert rD, rs1, Is3, Is2"));
71             InstallCustomInstruction(pattern: "1000000LLLLLSSSSS010DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Register, Operation.Insert, Width.Word, Sign.Unsigned, "p.insertr rD, rs1, rs2"));
72             InstallCustomInstruction(pattern: "11LLLLLLLLLLSSSSS011DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Clear, Width.Word, Sign.Unsigned, "p.bclr rD, rs1, Is3, Is2"));
73             InstallCustomInstruction(pattern: "1000000LLLLLSSSSS011DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Register, Operation.Clear, Width.Word, Sign.Unsigned, "p.bclrr rD, rs1, rs2"));
74             InstallCustomInstruction(pattern: "11LLLLLLLLLLSSSSS100DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Immediate, Operation.Set, Width.Word, Sign.Unsigned, "p.bset rD, rs1, Is3, Is2"));
75             InstallCustomInstruction(pattern: "1000000LLLLLSSSSS100DDDDD0110011", handler: opcode => ManipulateBitsInRegister(opcode, Source.Register, Operation.Set, Width.Word, Sign.Unsigned, "p.bsetr rD, rs1, rs2"));
76             InstallCustomInstruction(pattern: "JJJJJJJIIIIISSSSS010JJJJJ1100011", handler: opcode => BranchIf(opcode, Equality.Equal, "p.beqimm rs1, Imm5, Imm12"));
77             InstallCustomInstruction(pattern: "JJJJJJJIIIIISSSSS011JJJJJ1100011", handler: opcode => BranchIf(opcode, Equality.NotEqual, "p.bneimm rs1, Imm5, Imm12"));
78             InstallCustomInstruction(pattern: "0100001RRRRRSSSSS001DDDDD0110011", handler: opcode => MultiplyAccumulate(opcode, operationAdd: false, log: "p.msu rD, rs1, rs2"));
79             InstallCustomInstruction(pattern: "0100001RRRRRSSSSS000DDDDD0110011", handler: opcode => MultiplyAccumulate(opcode, operationAdd: true, log: "p.mac rD, rs1, rs2"));
80             InstallCustomInstruction(pattern: "00---------------001-----1011011", handler: _ => LogUnsupported("p.macuN rD, rs1, rs2, Is3"));
81             InstallCustomInstruction(pattern: "00---------------110-----1011011", handler: _ => LogUnsupported("p.mac.zh.zl"));
82             InstallCustomInstruction(pattern: "00---------------100-----1011011", handler: _ => LogUnsupported("p.mac.zl.zl"));
83             InstallCustomInstruction(pattern: "00---------------111-----1011011", handler: _ => LogUnsupported("p.mac.zh.zh"));
84             InstallCustomInstruction(pattern: "00---------------101-----1011011", handler: _ => LogUnsupported("p.mac.zl.zh"));
85             InstallCustomInstruction(pattern: "01---------------100-----1011011", handler: _ => LogUnsupported("p.mac.zl.sl"));
86             InstallCustomInstruction(pattern: "------------000000000000-1111011", handler: _ => LogUnsupported("lp.starti L, uimmL"));
87             InstallCustomInstruction(pattern: "------------000000010000-1111011", handler: _ => LogUnsupported("lp.endi L, uimmL"));
88             InstallCustomInstruction(pattern: "00---------------010-----1011011", handler: _ => LogUnsupported("p.addN rD, rs1, rs2, Is3"));
89             InstallCustomInstruction(pattern: "1100000----------010-----1011011", handler: _ => LogUnsupported("p.adduNr rD, rs1, rs"));
90             InstallCustomInstruction(pattern: "-----------------1000000-1111011", handler: _ => LogUnsupported("lp.setup L, rs1, uimmL"));
91             InstallCustomInstruction(pattern: "-----------------1010000-1111011", handler: _ => LogUnsupported("lp.setupi L, uimmS, uimmL"));
92             InstallCustomInstruction(pattern: "000000000000-----0100000-1111011", handler: _ => LogUnsupported("lp.count L, rs1"));
93             InstallCustomInstruction(pattern: "00---------------011-----1011011", handler: _ => LogUnsupported("p.subN rD, rs1, rs2, Is3"));
94             InstallCustomInstruction(pattern: "10---------------011-----1011011", handler: _ => LogUnsupported("p.subuN rD, rs1, rs2, Is3"));
95             InstallCustomInstruction(pattern: "10---------------000-----1011011", handler: _ => LogUnsupported("p.mulsN rD, rs1, rs2, Is3"));
96             InstallCustomInstruction(pattern: "01---------------000-----1011011", handler: _ => LogUnsupported("p.mulhhuN rD, rs1, rs2, Is3"));
97             InstallCustomInstruction(pattern: "11---------------000-----1011011", handler: _ => LogUnsupported("p.mulhhsN rD, rs1, rs2, Is3"));
98             InstallCustomInstruction(pattern: "000100000000-----001-----0110011", handler: _ => LogUnsupported("p.fl1 rD, rs1"));
99             InstallCustomInstruction(pattern: "-----------------110-----0000011", handler: _ => LogUnsupported("p.elw"));
100         }
101 
LogUnhandledCSRRead(string name)102         private ulong LogUnhandledCSRRead(string name)
103         {
104             this.Log(LogLevel.Error, "Reading from an unsupported CSR {0}", name);
105             return 0u;
106         }
107 
LogUnhandledCSRWrite(string name, ulong value)108         private void LogUnhandledCSRWrite(string name, ulong value)
109         {
110             this.Log(LogLevel.Error, "Writing to an unsupported CSR {0} value: 0x{1:X}", name, value);
111         }
112 
MultiplyAccumulate(ulong opcode, bool operationAdd, string log)113         private void MultiplyAccumulate(ulong opcode, bool operationAdd, string log)
114         {
115             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
116 
117             var rD = (int)BitHelper.GetValue(opcode, 7, 5);
118             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
119             var rs2 = (int)BitHelper.GetValue(opcode, 20, 5);
120 
121             var rDValue = (long)GetRegister(rD).RawValue;
122             var rs1Value = (long)GetRegister(rs1).RawValue;
123             var rs2Value = (long)GetRegister(rs2).RawValue;
124 
125             var result = (ulong)(operationAdd
126                 ? rDValue + rs1Value * rs2Value
127                 : rDValue - rs1Value * rs2Value);
128 
129             SetRegister(rD, result);
130         }
131 
LoadRegisterImmediate(ulong opcode, Width width, BitExtension extension, string log)132         private void LoadRegisterImmediate(ulong opcode, Width width, BitExtension extension, string log)
133         {
134             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
135             // rD = Sext/Zext(Mem8/16/32(rs1))
136             // rs1 += Imm[11:0]
137             // It seems that Imm should be extended, but the docs do not confirm it explicitly
138             var imm = (int)BitHelper.SignExtend((uint)BitHelper.GetValue(opcode, 20, 12), 12);
139             var rD = (int)BitHelper.GetValue(opcode, 7, 5);
140             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
141             var rs1Value = (long)GetRegister(rs1).RawValue;
142             SetRegister(rD, GetMemValue(width, extension, (ulong)rs1Value));
143             SetRegister(rs1, (ulong)(rs1Value + imm));
144         }
145 
LoadRegisterRegister(ulong opcode, Width width, BitExtension extension, string log, bool postIncrement = false)146         private void LoadRegisterRegister(ulong opcode, Width width, BitExtension extension, string log, bool postIncrement = false)
147         {
148             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
149             // with post-increment:
150             // rD = Sext/Zext(Mem8/16/32(rs1))
151             // rs1 += rs2
152             // without post-increment:
153             // rD = Sext/Zext(Mem8/16/32(rs1 + rs2))
154             var rD = (int)BitHelper.GetValue(opcode, 7, 5);
155             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
156             var rs1Value = GetRegister(rs1).RawValue;
157             var rs2 = (int)BitHelper.GetValue(opcode, 20, 5);
158             var rs2Value = GetRegister(rs2).RawValue;
159             SetRegister(rD, GetMemValue(width, extension, postIncrement ? rs1Value : rs1Value + rs2Value));
160             if(postIncrement)
161             {
162                 SetRegister(rs1, rs1Value + rs2Value);
163             }
164         }
165 
StoreRegisterImmediate(ulong opcode, Width width, string log)166         private void StoreRegisterImmediate(ulong opcode, Width width, string log)
167         {
168             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
169             // Mem8/16/32(rs1) = rs2
170             // rs1 += Imm[11:0]
171             var imm = (int)BitHelper.SignExtend((uint)((BitHelper.GetValue(opcode, 25, 7) << 5) | BitHelper.GetValue(opcode, 7, 5)), 12);
172             var rs2 = (int)BitHelper.GetValue(opcode, 20, 5);
173             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
174             var rs2Value = GetRegister(rs2).RawValue;
175             var rs1Value = (long)GetRegister(rs1).RawValue;
176             SetMemValue(width, rs2Value, (ulong)rs1Value);
177             SetRegister(rs1, (ulong)(rs1Value + imm));
178         }
179 
StoreRegisterRegister(ulong opcode, Width width, string log, bool postIncrement = false)180         private void StoreRegisterRegister(ulong opcode, Width width, string log, bool postIncrement = false)
181         {
182             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
183             // with post-increment:
184             // Mem8/16/32(rs1) = rs2
185             // rs1 += rs3
186             // without post-increment:
187             // Mem8/16/32(rs1 + rs3) = rs2
188             var rs2 = (int)BitHelper.GetValue(opcode, 20, 5);
189             var rs3 = (int)BitHelper.GetValue(opcode, 7, 5);
190             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
191             var rs1Value = GetRegister(rs1).RawValue;
192             var rs3Value = GetRegister(rs3).RawValue;
193             var rs2Value = GetRegister(rs2).RawValue;
194             SetMemValue(width, rs2Value, postIncrement ? rs1Value : rs1Value + rs3Value);
195             if(postIncrement)
196             {
197                 SetRegister(rs1, rs1Value + rs3Value);
198             }
199         }
200 
CompareRegisters(ulong opcode, ComparisonType type, Sign sign, string log)201         private void CompareRegisters(ulong opcode, ComparisonType type, Sign sign, string log)
202         {
203             this.Log(LogLevel.Noisy, "({0}) at PC=0x{1:X}", log, PC.RawValue);
204             var rD = (int)BitHelper.GetValue(opcode, 7, 5);
205             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
206             var rs1Value = GetRegister(rs1).RawValue;
207             var rs2 = (int)BitHelper.GetValue(opcode, 20, 5);
208             var rs2Value = GetRegister(rs2).RawValue;
209             var result = 0UL;
210             if(type == ComparisonType.Min && sign == Sign.Signed)
211             {
212                 result = (int)rs1Value < (int)rs2Value ? rs1Value : rs2Value;
213             }
214             else if(type == ComparisonType.Min && sign == Sign.Unsigned)
215             {
216                 result = rs1Value < rs2Value ? rs1Value : rs2Value;
217             }
218             else if(type == ComparisonType.Max && sign == Sign.Signed)
219             {
220                 result = (int)rs1Value < (int)rs2Value ? rs2Value : rs1Value;
221             }
222             else if(type == ComparisonType.Max && sign == Sign.Unsigned)
223             {
224                 result = rs1Value < rs2Value ? rs2Value : rs1Value;
225             }
226             else
227             {
228                 this.Log(LogLevel.Error, "Could not execute compare instruction: {0}", log);
229             }
230             SetRegister(rD, result);
231         }
232 
ManipulateBitsInRegister(ulong opcode, Source source, Operation operation, Width width, Sign sign, string log)233         private void ManipulateBitsInRegister(ulong opcode, Source source, Operation operation, Width width, Sign sign, string log)
234         {
235             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
236             var rD = (int)BitHelper.GetValue(opcode, 7, 5);
237             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
238             var is2 = (int)BitHelper.GetValue(opcode, 20, 5);
239             var is3 = (int)BitHelper.GetValue(opcode, 25, 5);
240             var rs1Value = GetRegister(rs1).RawValue;
241             if(source == Source.Register)
242             {
243                 var rs2 = (int)BitHelper.GetValue(opcode, 20, 5);
244                 var rs2Value = GetRegister(rs2).RawValue;
245                 is2 = (int)BitHelper.GetValue(rs2Value, 0, 5);
246                 is3 = (int)BitHelper.GetValue(rs2Value, 5, 5);
247             }
248             var rDValue = GetRegister(rD).RawValue;
249             if(is2 + is3 > 32)
250             {
251                 this.Log(LogLevel.Error, "Sum of operands Is3 an Is2 is equal to {0} but should not be larger than 32", is2 + is3);
252                 return;
253             }
254             var result = 0UL;
255             switch(operation)
256             {
257                 case Operation.Set:
258                     // p.bset:
259                     // rD = rs1 | (((1 << (Is3 + 1)) - 1) << Is2)
260                     // p.bsetr:
261                     // rD = rs1 | (((1 << (rs2[9:5]+1)) - 1) << rs2[4:0])
262                     result = rs1Value | ((ulong)((1 << (is3 + 1)) - 1) << is2);
263                     break;
264                 case Operation.Insert:
265                     // p.insert:
266                     // rD = rD | (rs1[Is3:0] << Is2)
267                     // p.insertr:
268                     // rD = rD | (rs1[rs2[9:5]:0] << rs2[4:0])
269                     result = rDValue | (BitHelper.GetValue(rs1Value, 0, is3 + 1) << is2);
270                     break;
271                 case Operation.Extract:
272                     result = ExtractBits(width, sign, is2, is3, rs1Value);
273                     break;
274                 case Operation.Clear:
275                     // p.bclr:
276                     // rD = rs1 & ~(((1 << (Is3 + 1)) - 1) << Is2)
277                     // p.bclrr:
278                     // rD = rs1 & ~(((1 << (rs2[9:5]+1)) - 1) << rs2[4:0])
279                     result = rs1Value & (~(ulong)(((1 << (is3 + 1)) - 1) << is2));
280                     break;
281                 default:
282                     this.Log(LogLevel.Error, "Encountered an unexpected option: {0}", sign);
283                     break;
284             }
285             SetRegister(rD, result);
286         }
287 
BranchIf(ulong opcode, Equality equality, string log)288         private void BranchIf(ulong opcode, Equality equality, string log)
289         {
290             this.Log(LogLevel.Noisy, "({0}) at PC={1:X}", log, PC.RawValue);
291             var rs1 = (int)BitHelper.GetValue(opcode, 15, 5);
292             var rs1Value = (long)GetRegister(rs1).RawValue;
293             var imm5 = (int)BitHelper.SignExtend((uint)BitHelper.GetValue(opcode, 20, 5), 5);
294             if((equality == Equality.NotEqual && rs1Value != imm5) || (equality == Equality.Equal && rs1Value == imm5))
295             {
296                 var imm12 = (int)BitHelper.SignExtend((uint)((BitHelper.GetValue(opcode, 31, 1) << 11) | (BitHelper.GetValue(opcode, 7, 1) << 10) | (BitHelper.GetValue(opcode, 25, 6) << 4) | BitHelper.GetValue(opcode, 8, 4)), 12);
297                 var newPC = (uint)((uint)GetRegister((int)RiscV32Registers.PC).RawValue + (imm12 << 1));
298                 PC = newPC;
299             }
300         }
301 
ExtractBits(Width width, Sign sign, int is2, int is3, ulong rs1Value)302         private ulong ExtractBits(Width width, Sign sign, int is2, int is3, ulong rs1Value)
303         {
304             // This seems to be contradicting the documentation, but experimentally
305             // makes things work.
306             is3++;
307             var result = 0UL;
308             switch(width)
309             {
310                 case Width.Byte:
311                     // p.extbs rD, rs1
312                     // rD = Sext(rs1[7:0])
313                     // p.extbz rD, rs1
314                     // rD = Zext(rs1[7:0])
315                     result = sign == Sign.Signed
316                         ? BitHelper.SignExtend((uint)BitHelper.GetValue(rs1Value, 0, 8), 8)
317                         : BitHelper.GetValue(rs1Value, 0, 8);
318                     break;
319                 case Width.HalfWord:
320                     // p.exths rD, rs1
321                     // rD = Sext(rs1[15:0])
322                     // p.exthz rD, rs1
323                     // rD = Zext(rs1[15:0])
324                     result = sign == Sign.Signed
325                         ? BitHelper.SignExtend((uint)BitHelper.GetValue(rs1Value, 0, 16), 16)
326                         : BitHelper.GetValue(rs1Value, 0, 16);
327                     break;
328                 case Width.Word:
329                     // p.extract rD, rs1, Is3, Is2
330                     // rD = Sext((rs1 & ((1 << Is3) - 1) << Is2) >> Is2)
331                     // p.extractu rD, rs1, Is3, Is2
332                     // rD = Zext((rs1 & ((1 << Is3) - 1) << Is2) >> Is2)
333                     // p.extractr rD, rs1, rs2
334                     // rD = Sext((rs1 & ((1 << rs2[9:5]) - 1) << rs2[4:0]) >> rs2[4:0])
335                     // p.extractur rD, rs1, rs2
336                     // rD = Zext((rs1 & ((1 << rs2[9:5]) - 1) << rs2[4:0]) >> rs2[4:0])
337                     var temp = ((int)rs1Value & ((1 << is3) - 1) << is2) >> is2;
338                     result = sign == Sign.Signed
339                         ? BitHelper.SignExtend((uint)temp, 32 - is2)
340                         : (uint)temp;
341                     break;
342                 default:
343                     this.Log(LogLevel.Error, "Encountered an unexpected option: {0}", sign);
344                     break;
345             }
346             return result;
347         }
348 
SetMemValue(Width width, ulong value, ulong address)349         private void SetMemValue(Width width, ulong value, ulong address)
350         {
351             switch(width)
352             {
353                 case Width.Byte:
354                     WriteByteToBus(address, (uint)value);
355                     break;
356                 case Width.HalfWord:
357                     WriteWordToBus(address, (uint)value);
358                     break;
359                 case Width.Word:
360                     WriteDoubleWordToBus(address, (uint)value);
361                     break;
362                 default:
363                     this.Log(LogLevel.Error, "Encountered an unexpected option: {0}", width);
364                     break;
365             }
366         }
367 
GetMemValue(Width width, BitExtension extension, ulong address)368         private ulong GetMemValue(Width width, BitExtension extension, ulong address)
369         {
370             var mem = 0UL;
371             switch(width)
372             {
373                 case Width.Byte:
374                     mem = extension == BitExtension.Sign ? BitHelper.SignExtend(ReadByteFromBus(address), 8) : ReadByteFromBus(address);
375                     break;
376                 case Width.HalfWord:
377                     mem = extension == BitExtension.Sign ? BitHelper.SignExtend(ReadWordFromBus(address), 16) : ReadWordFromBus(address);
378                     break;
379                 case Width.Word:
380                     mem = ReadDoubleWordFromBus(address);
381                     break;
382                 default:
383                     this.Log(LogLevel.Error, "Encountered an unexpected option: {0}", width);
384                     break;
385             }
386             return mem;
387         }
388 
LogUnsupported(string text)389         private void LogUnsupported(string text)
390         {
391             this.Log(LogLevel.Error, "Encountered unsupported instruction: ({0}) at PC={1:X}", text, PC);
392         }
393 
394         private enum Equality
395         {
396             Equal,
397             NotEqual
398         }
399 
400         private enum ComparisonType
401         {
402             Max,
403             Min
404         }
405 
406         private enum Sign
407         {
408             Signed,
409             Unsigned
410         }
411 
412         private enum Width
413         {
414             Byte,
415             HalfWord,
416             Word
417         }
418 
419         private enum Operation
420         {
421             Extract,
422             Insert,
423             Clear,
424             Set
425         }
426 
427         private enum Source
428         {
429             Register,
430             Immediate
431         }
432         private enum BitExtension
433         {
434             Sign,
435             Zero
436         }
437 
438         private enum CustomCSR
439         {
440             PerformanceCounterMode = 0x7a1,
441             StackCheckEnable = 0x7d0,
442             StackBase = 0x7d1,
443             StackEnd = 0x7d2,
444             HardwareLoop0Start = 0x7c0,
445             HardwareLoop0End = 0x7c1,
446             HardwareLoop0Counter = 0x7c2,
447             HardwareLoop1Start = 0x7c4,
448             HardwareLoop1End = 0x7d5,
449             HardwareLoop1Counter = 0x7d6
450         }
451     }
452 }
453