1 //
2 // Copyright (c) 2010-2023 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 
8 using System;
9 using System.Collections.Generic;
10 using System.Linq;
11 using Antmicro.Renode.Utilities.Collections;
12 using Antmicro.Renode.Core;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Utilities;
15 using Antmicro.Renode.Logging;
16 
17 namespace Antmicro.Renode.Peripherals.Miscellaneous
18 {
19     public class EOSS3_PacketFIFO : BasicDoubleWordPeripheral, IKnownSize
20     {
EOSS3_PacketFIFO(IMachine machine)21         public EOSS3_PacketFIFO(IMachine machine) : base(machine)
22         {
23             queueNames = new Dictionary<long, string>()
24             {
25                 {0, "PacketFifo0"},
26                 {1, "PacketFifo1"},
27                 {2, "PacketFifo2"},
28                 {3, "PacketFifo8k"}
29             };
30 
31             packetFifos = new PacketFifoBase[NumberOfQueues];
32 
33             for(var i = 0; i < NumberOfRegularQueues; i ++)
34             {
35                 packetFifos[i] = new PacketFifo(this, queueNames[i], fifoSizes[i]);
36             }
37 
38             packetFifos[NumberOfQueues - 1] = new PacketFifoSwitchable(this, queueNames[NumberOfQueues - 1], fifoSizes[NumberOfQueues - 1]);
39 
40             DefineRegisters();
41         }
42 
43         public long Size => 0x2000;
44 
45         /*
46                 Collision is not to be implemented
47                 Ram is always awake.
48         */
49         public GPIO IRQ { get; } = new GPIO();
50 
DefineRegisters()51         private void DefineRegisters()
52         {
53             var loopHelper = Registers.FifoControl.Define(this);
54             for(var i = 0; i < 31; i += 8)
55             {
56                 loopHelper
57                     .WithFlag(i, out enable[i / 8], writeCallback: WarnUnsupportedMux, name: queueNames[i / 8] + "_en")
58                     .WithFlag(i + 0x1, out pushMux[i / 8], writeCallback: WarnUnsupportedMux, name: queueNames[i / 8] + "_push_mux")
59                     .WithFlag(i + 0x2, out popMux[i / 8], writeCallback: WarnUnsupportedMux, name: queueNames[i / 8] + "_pop_mux")
60                     .WithFlag(i + 0x3, out pushIntMux[i / 8], writeCallback: WarnUnsupportedMux, name: queueNames[i / 8] + "_push_int_mux")
61                     .WithFlag(i + 0x4, out popIntMux[i / 8], writeCallback: WarnUnsupportedMux, name: queueNames[i / 8] + "_pop_int_mux")
62                     .WithTaggedFlag(queueNames[i/8] + "_ffe_sel", i + 0x5);
63             }
64             loopHelper.WithReservedBits(30, 2);
65 
66             loopHelper = Registers.FifoStatus.Define(this);
67             for(var i = 0; i < 31; i += 8)
68             {
69                 loopHelper
70                     .WithValueField(i + 0x0, 2, valueProviderCallback: _ => 0x0, name: queueNames[i / 8] + "_sram_sleep" ) //will never sleep
71                     .WithFlag(i + 0x2, out packetFifos[i / 8].Overflow, FieldMode.WriteOneToClear | FieldMode.Read, writeCallback: UpdateIRQWrapper, name: queueNames[i / 8] + "_push_int_over")
72                     .WithFlag(i + 0x3, out packetFifos[i / 8].PushThreshold, FieldMode.Read, name:  queueNames[i / 8] + "_push_int_thresh")
73                     .WithFlag(i + 0x4, out packetFifos[i / 8].PushOnSleep, FieldMode.WriteOneToClear | FieldMode.Read, writeCallback: UpdateIRQWrapper, name: queueNames[i / 8] + "_push_int_sleep")
74                     .WithFlag(i + 0x5, out packetFifos[i / 8].Underflow, FieldMode.WriteOneToClear | FieldMode.Read, writeCallback: UpdateIRQWrapper, name: queueNames[i / 8] + "_pop_int_under")
75                     .WithFlag(i + 0x6, out packetFifos[i / 8].PopThreshold, FieldMode.Read, name:  queueNames[i / 8] + "_pop_int_thresh")
76                     .WithFlag(i + 0x7, out packetFifos[i / 8].PopOnSleep, FieldMode.WriteOneToClear | FieldMode.Read, writeCallback: UpdateIRQWrapper, name: queueNames[i / 8] + "_pop_int_sleep");
77             }
78 
79             Registers.PushControlPacketFifo0.DefineMany(this, NumberOfQueues, (reg, idx) =>
80                 reg.WithTaggedFlag(queueNames[idx] + "_push_sleep_en", 0x0)
81                 .WithTaggedFlag(queueNames[idx] + "_push_sleep_type", 0x1)
82                 .WithFlag(0x2, out packetFifos[idx].PushOverMask, writeCallback: UpdateIRQWrapper, name: queueNames[idx] + "_push_int_en_over")
83                 .WithFlag(0x3, out packetFifos[idx].PushThresholdMask, writeCallback: UpdateIRQWrapper, name: queueNames[idx] + "_push_int_en_thresh")
84                 .WithTaggedFlag(queueNames[idx] + "_push_int_en_sram_sleep", 0x4)
85                 .WithValueField(0x10, 9, out packetFifos[idx].PushThresholdLevel, name: queueNames[idx] + "_push_thresh")
86                 .WithReservedBits(25, 7)
87             , 0x10);
88 
89             Registers.PopControlPacketFifo0.DefineMany(this, NumberOfRegularQueues, (reg, idx) =>
90                 reg.WithTaggedFlag(queueNames[idx] + "_pop_sleep_en", 0x0)
91                 .WithTaggedFlag(queueNames[idx] + "_pop_sleep_type", 0x1)
92                 .WithFlag(0x2, flagField: out packetFifos[idx].PopUnderMask, writeCallback: UpdateIRQWrapper, name: queueNames[idx] + "_pop_int_en_under")
93                 .WithFlag(0x3, flagField: out packetFifos[idx].PopThresholdMask, writeCallback: UpdateIRQWrapper, name: queueNames[idx] + "_pop_int_en_thresh")
94                 .WithTaggedFlag(queueNames[idx] + "_push_int_en_sram_sleep", 0x4)
95                 .WithValueField(0x10, 9, out packetFifos[idx].PopThresholdLevel, name: queueNames[idx] + "_pop_thresh")
96                 .WithReservedBits(25, 7)
97             , 0x10);
98 
99             Registers.PopControlPacketFifo8k.Define(this)
100                 .WithTaggedFlag(queueNames[3] + "_pop_sleep_en", 0x0)
101                 .WithTaggedFlag(queueNames[3] + "_pop_sleep_type", 0x1)
102                 .WithFlag(0x2, flagField: out packetFifos[3].PopUnderMask, writeCallback: UpdateIRQWrapper, name: queueNames[3] + "_pop_int_en_under")
103                 .WithFlag(0x3, flagField: out packetFifos[3].PopThresholdMask, writeCallback: UpdateIRQWrapper, name: queueNames[3] + "_pop_int_en_thresh")
104                 .WithFlag(0x5, writeCallback: ((PacketFifoSwitchable) packetFifos[3]).EnableFifoMode, valueProviderCallback: _ => ((PacketFifoSwitchable) packetFifos[3]).pf8kFifoMode, name: queueNames[3] + "_fifo_pkt_mode")
105                 .WithFlag(0x6, writeCallback: ((PacketFifoSwitchable) packetFifos[3]).EnableRingMode, valueProviderCallback: _ => ((PacketFifoSwitchable) packetFifos[3]).pf8kRingBuffMode, name: queueNames[3] + "_fifo_ring_buff_mode")
106                 .WithValueField(0x10, 13, out packetFifos[3].PopThresholdLevel, name: queueNames[3] + "_pop_thresh")
107                 .WithReservedBits(29, 3);
108 
109             Registers.CountPacketFifo0.Define(this)
110                 .WithValueField(0x0, 9, FieldMode.Read, valueProviderCallback: _ => (uint)(packetFifos[0].Count), name: queueNames[0] + "_pop_cnt")
111                 .WithFlag(0xF, FieldMode.Read, valueProviderCallback: _ => (packetFifos[0].Count == 0), name: queueNames[0] + "_empty")
112                 .WithValueField(0x10, 9, FieldMode.Read, valueProviderCallback: _ => (uint)(fifoSizes[0] - packetFifos[0].Count), name: queueNames[0] + "_push_cnt")
113                 .WithFlag(0x1F, FieldMode.Read, valueProviderCallback: _ => (packetFifos[0].Count >= fifoSizes[0]), name: queueNames[0] + "_full");
114 
115             Registers.CountPacketFifo1.DefineMany(this, 3, (reg, idx) =>
116                 reg.WithValueField(0x0, 8, FieldMode.Read, valueProviderCallback: _ => (uint)(packetFifos[idx].Count), name: queueNames[idx] + "_pop_cnt")
117                 .WithFlag(0xF, FieldMode.Read, valueProviderCallback: _ => (packetFifos[idx].Count == 0), name: queueNames[idx] + "_empty")
118                 .WithValueField(0x10, 8, FieldMode.Read, valueProviderCallback: _ => (uint)(fifoSizes[idx] - packetFifos[idx].Count), name: queueNames[idx] + "_push_cnt")
119                 .WithFlag(0x1F, FieldMode.Read, valueProviderCallback: _ => (packetFifos[idx].Count >= fifoSizes[idx]), name: queueNames[idx] + "_full")
120             , 0x10);
121 
122             Registers.DataPacketFifo0.DefineMany(this, NumberOfRegularQueues, (reg, idx) =>
123                 reg.WithValueField(0x0, 32, writeCallback: (prevVal, val) => packetFifos[idx].EnqueueCallback((uint)prevVal, (uint)val), valueProviderCallback: (prevVal) => packetFifos[idx].DequeueCallback((uint)prevVal), name: queueNames[idx] + "_data_reg")
124             , 0x10);
125 
126             Registers.DataPacketFifo8k.Define(this)
127                 .WithValueField(0x0, 17, writeCallback: (prevVal, val) => packetFifos[3].EnqueueCallback((uint)prevVal, (uint)val), valueProviderCallback: (prevVal) => packetFifos[3].DequeueCallback((uint)prevVal), name: queueNames[3] + "_data_reg")
128                 .WithFlag(0x11, name: queueNames[3] + "_push_eop")
129                 .WithReservedBits(18, 14);
130         }
131 
132 
WarnUnsupportedMux(bool _, bool value)133         private void WarnUnsupportedMux(bool _, bool value)
134         {
135             if(value)
136             {
137                 this.Log(LogLevel.Warning, "This target is unsupported.", value);
138             }
139         }
140 
UpdateIRQWrapper(bool _, bool __)141         private void UpdateIRQWrapper(bool _, bool __)
142         {
143             UpdateIRQ();
144         }
145 
UpdateIRQ()146         private void UpdateIRQ()
147         {
148             foreach(var queue in packetFifos)
149             {
150                 if(queue.PushOverMask.Value && queue.Overflow.Value
151                     || queue.PushThresholdMask.Value && queue.PushThreshold.Value
152                     || queue.PopUnderMask.Value && queue.Underflow.Value
153                     || queue.PopThresholdMask.Value && queue.PopThreshold.Value)
154                     {
155                         IRQ.Set(true);
156                         return;
157                     }
158             }
159             IRQ.Unset();
160         }
161 
162         private PacketFifoBase[] packetFifos;
163 
164         private readonly int[] fifoSizes = {256, 128, 128, 4096};
165 
166         private Dictionary<long, string> queueNames;
167 
168         private IFlagRegisterField[] enable = new IFlagRegisterField[4];
169         private IFlagRegisterField[] pushMux = new IFlagRegisterField[4];
170         private IFlagRegisterField[] popMux = new IFlagRegisterField[4];
171         private IFlagRegisterField[] pushIntMux = new IFlagRegisterField[4];
172         private IFlagRegisterField[] popIntMux = new IFlagRegisterField[4];
173 
174         private const int NumberOfQueues = 4;
175         private const int NumberOfRegularQueues = 3;
176 
177         private abstract class PacketFifoBase
178         {
PacketFifoBase(EOSS3_PacketFIFO parent, string name, int size)179             public PacketFifoBase(EOSS3_PacketFIFO parent, string name, int size)
180             {
181                 this.parent = parent;
182                 this.name = name;
183                 this.size = size;
184             }
185 
EnqueueCallback(uint _, uint value)186             public abstract void EnqueueCallback(uint _, uint value);
DequeueCallback(uint _)187             public abstract uint DequeueCallback(uint _);
188 
189             public abstract int Count { get; protected set;}
190 
191             public IFlagRegisterField PushOverMask; //mask on 0, enable on 1
192             public IFlagRegisterField PushThresholdMask;
193             public IValueRegisterField PushThresholdLevel;
194             public IFlagRegisterField PopUnderMask;
195             public IFlagRegisterField PopThresholdMask;
196             public IValueRegisterField PopThresholdLevel;
197 
198             public IFlagRegisterField Overflow;
199             public IFlagRegisterField Underflow;
200             public IFlagRegisterField PushThreshold;
201             public IFlagRegisterField PushOnSleep;
202             public IFlagRegisterField PopThreshold;
203             public IFlagRegisterField PopOnSleep; //no collision, as it is not simulated
204 
205             protected String name;
206             protected int size;
207             protected EOSS3_PacketFIFO parent;
208         }
209 
210         private class PacketFifo : PacketFifoBase
211         {
PacketFifo(EOSS3_PacketFIFO parent, string name, int size)212             public PacketFifo(EOSS3_PacketFIFO parent, string name, int size) : base(parent, name, size)
213             {
214                 fifo = new Queue<UInt32>();
215             }
216 
EnqueueCallback(uint _, uint value)217             public override void EnqueueCallback(uint _, uint value)
218             {
219                 PopThreshold.Value = false;
220 
221                 fifo.Enqueue(value);
222                 if(fifo.Count >= (int)PushThresholdLevel.Value)
223                 {
224                     PushThreshold.Value = true;
225                     parent.Log(LogLevel.Noisy, "Push treshold in {0}.", name);
226                 }
227                 if(fifo.Count > size)
228                 {
229                     Overflow.Value = true;
230                     parent.Log(LogLevel.Warning, "Cannot push {0}: maximum size exceeded.", name);
231                 }
232                 else
233                 {
234                     Overflow.Value = false;
235                 }
236                 parent.UpdateIRQ();
237             }
238 
DequeueCallback(uint _)239             public override uint DequeueCallback(uint _)
240             {
241                 PushThreshold.Value = false;
242 
243                 if(fifo.Count == 0)
244                 {
245                     Underflow.Value = true;
246                     parent.Log(LogLevel.Warning, "Cannot pop: {0} is empty.", name);
247                     parent.UpdateIRQ();
248                     return 0;
249                 }
250                 else
251                 {
252                     Underflow.Value = false;
253                 }
254                 if(fifo.Count - 1 <= (int)PopThresholdLevel.Value)
255                 {
256                     PopThreshold.Value = true;
257                     parent.Log(LogLevel.Noisy, "Pop treshold in {0}.", name);
258                 }
259                 parent.UpdateIRQ();
260                 return fifo.Dequeue();
261             }
262 
263             public override int Count
264             {
265                 get {return fifo.Count;}
266                 protected set {}
267             }
268 
269             private Queue<UInt32> fifo;
270         }
271 
272         private class PacketFifoSwitchable : PacketFifoBase
273         {
PacketFifoSwitchable(EOSS3_PacketFIFO pf, string name, int size)274             public PacketFifoSwitchable(EOSS3_PacketFIFO pf, string name, int size) : base(pf, name, size)
275             {
276                 pf3BufferMode = new CircularBuffer<UInt16>(size);
277                 pf3QueueMode = new Queue<UInt16>(size);
278             }
279 
EnableFifoMode(bool _, bool value)280             public void EnableFifoMode(bool _, bool value)
281             {
282                 pf8kFifoMode = value;
283                 if(value && !pf8kRingBuffMode)
284                 {
285                     pf3QueueMode = new Queue<UInt16> (pf3BufferMode);
286 
287                     parent.Log(LogLevel.Noisy, "Switched {0} to FIFO mode", name);
288                 }
289             }
290 
EnableRingMode(bool _, bool value)291             public void EnableRingMode(bool _, bool value)
292             {
293                 pf8kRingBuffMode = value;
294                 if(value && !pf8kFifoMode)
295                 {
296                     var size = Math.Max(pf3QueueMode.Count, 4096);
297                     pf3BufferMode = new CircularBuffer<UInt16> (size);
298 
299                     foreach(var element in pf3QueueMode)
300                     {
301                         pf3BufferMode.Enqueue(element);
302                     }
303 
304                     parent.Log(LogLevel.Noisy, "Switched {0} to ring buffer mode", name);
305                 }
306             }
307 
EnqueueCallback(uint _, uint value)308             public override void EnqueueCallback(uint _, uint value)
309             {
310                 PopThreshold.Value = false;
311 
312                 if(pf8kRingBuffMode && !pf8kFifoMode)
313                 {
314                     pf3BufferMode.Enqueue((ushort)value);
315                     if(pf3BufferMode.Count >= (int)PushThresholdLevel.Value)
316                     {
317                         PushThreshold.Value = true;
318                         parent.Log(LogLevel.Noisy, "Push treshold in {0}.", name);
319                     }
320                     if(pf3BufferMode.Count > size)
321                     {
322                         parent.Log(LogLevel.Warning, "Cannot push {0}: maximum size exceeded.", name);
323                     }
324                 }
325                 else if(!pf8kRingBuffMode && pf8kFifoMode)
326                 {
327                     pf3QueueMode.Enqueue((ushort)value);
328                     if(pf3QueueMode.Count >= (int)PushThresholdLevel.Value)
329                     {
330                         PushThreshold.Value = true;
331                         parent.Log(LogLevel.Noisy, "Push treshold in {0}", name);
332                     }
333                     if(pf3QueueMode.Count > size)
334                     {
335                         Overflow.Value = true;
336                         parent.Log(LogLevel.Warning, "Cannot push {0}: maximum size exceeded.", name);
337                     }
338                     else
339                     {
340                         Overflow.Value = false;
341                     }
342                 }
343                 else
344                 {
345                     parent.Log(LogLevel.Warning, "No valid mode for {0} selected", name);
346                 }
347                 parent.UpdateIRQ();
348             }
349 
DequeueCallback(uint _)350             public override uint DequeueCallback(uint _)
351             {
352                 PushThreshold.Value = false;
353 
354                 if(pf8kRingBuffMode && !pf8kFifoMode)
355                 {
356                     if(pf3BufferMode.Count == 0)
357                     {
358                         Underflow.Value = true;
359                         parent.Log(LogLevel.Warning, "Cannot pop: {0} is empty.", name);
360                         parent.UpdateIRQ();
361                         return 0;
362                     }
363                     else
364                     {
365                         Underflow.Value = false;
366                     }
367                     if(pf3BufferMode.Count - 1 <= (int)PopThresholdLevel.Value)
368                     {
369                         PopThreshold.Value = true;
370                         parent.Log(LogLevel.Noisy, "Pop treshold in {0}.", name);
371                     }
372                     parent.UpdateIRQ();
373                     return pf3BufferMode.TryDequeue(out var ret) ? ret : 0u;
374                 }
375                 else if(!pf8kRingBuffMode && pf8kFifoMode)
376                 {
377                     if(pf3QueueMode.Count == 0)
378                     {
379                         Underflow.Value = true;
380                         parent.Log(LogLevel.Warning, "Cannot pop: {0} is empty.", name);
381                         parent.UpdateIRQ();
382                         return 0;
383                     }
384                     else
385                     {
386                         Underflow.Value = false;
387                     }
388                     if(pf3QueueMode.Count - 1 <= (int)PopThresholdLevel.Value)
389                     {
390                         PopThreshold.Value = true;
391                         parent.Log(LogLevel.Noisy, "Pop treshold in {0}.", name);
392                     }
393                     parent.UpdateIRQ();
394                     return pf3QueueMode.TryDequeue(out var ret) ? ret : 0u;
395                 }
396                 else
397                 {
398                     parent.Log(LogLevel.Warning, "No valid mode for {0} selected", name);
399                     parent.UpdateIRQ();
400                     return 0;
401                 }
402             }
403 
404             public override int Count
405             {
406                 get
407                 {
408                     if(pf8kFifoMode)
409                     {
410                         return pf3QueueMode.Count;
411                     }
412                     if(pf8kRingBuffMode)
413                     {
414                         return pf3BufferMode.Count;
415                     }
416                     return 0;
417                 }
418                 protected set {}
419             }
420 
421             public bool pf8kFifoMode;
422             public bool pf8kRingBuffMode;
423             private Queue<UInt16> pf3QueueMode;
424             private CircularBuffer<UInt16> pf3BufferMode;
425         }
426 
427         private enum EPushMux
428         {
429             M4 = 0x0, //Memory
430             FFE = 0x1 //FFE
431         }
432 
433         private enum EOthersMux
434         {
435             M4 = 0x0, //Memory
436             AP = 0x1, //Applications Processor
437         }
438 
439         private enum Registers
440         {
441             FifoControl = 0x0,
442             SramControl0 = 0x004,
443             SramControl1 = 0x008,
444             FifoStatus = 0x00C,
445             PushControlPacketFifo0 = 0x010,
446             PopControlPacketFifo0 = 0x014,
447             CountPacketFifo0 = 0x018,
448             DataPacketFifo0 = 0x01C,
449             PushControlPacketFifo1 = 0x020,
450             PopControlPacketFifo1 = 0x024,
451             CountPacketFifo1 = 0x028,
452             DataPacketFifo1 = 0x02C,
453             PushControlPacketFifo2 = 0x030,
454             PopControlPacketFifo2 = 0x034,
455             CountPacketFifo2 = 0x038,
456             DataPacketFifo2 = 0x03C,
457             PushControlPacketFifo8k = 0x040,
458             PopControlPacketFifo8k = 0x044,
459             CountPacketFifo8k = 0x048,
460             DataPacketFifo8k = 0x04C,
461             FifoCollisionInterrupts = 0x050,
462             FifoCollisionMasks = 0x54
463         }
464     }
465 }
466