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