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 using System.Collections.Generic; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Utilities.Collections; 14 15 namespace Antmicro.Renode.Peripherals.SPI 16 { 17 public class CC2538_SSI : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IDoubleWordPeripheral, IKnownSize 18 { CC2538_SSI(IMachine machine)19 public CC2538_SSI(IMachine machine) : base(machine) 20 { 21 IRQ = new GPIO(); 22 23 rxFifo = new CircularBuffer<byte>(FifoCapacity); 24 txFifo = new CircularBuffer<byte>(FifoCapacity); 25 26 var regs = new Dictionary<long, DoubleWordRegister> 27 { 28 { (long)Registers.Control0, new DoubleWordRegister(this) 29 .WithValueField(0, 4, writeCallback: (_, value) => { 30 if(value <= 2) 31 { 32 this.Log(LogLevel.Warning, "Trying to set as reserved value of DSS: {0}", value); 33 } 34 else if(value != 7) //8-bit data 35 { 36 this.Log(LogLevel.Warning, "An unsupported data size {0} set, only 7 (8 bits) is legal.", value); 37 } 38 }, name: "DSS") 39 .WithTag("FRF", 4, 2) 40 .WithTaggedFlag("SPO", 6) 41 .WithTaggedFlag("SPH", 7) 42 .WithTag("SCR", 8, 8) 43 .WithReservedBits(16, 16) 44 }, 45 { (long)Registers.Control1, new DoubleWordRegister(this) 46 .WithTaggedFlag("LBM", 0) 47 .WithFlag(1, out enabled, writeCallback: EnableTransmitter, name: "SSE") 48 .WithTaggedFlag("MS", 2) 49 .WithTaggedFlag("SOD", 3) 50 .WithReservedBits(4, 28) 51 }, 52 { (long)Registers.Data, new DoubleWordRegister(this) 53 .WithValueField(0, 16, valueProviderCallback: _ => rxFifo.TryDequeue(out var val) ? val : 0u, writeCallback: (_, value) => SendData((uint)value), name: "DATA") 54 .WithReservedBits(16, 16) 55 .WithReadCallback((_, __) => Update()) 56 }, 57 { (long)Registers.Status, new DoubleWordRegister(this) 58 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => txFifo.Count == 0, name: "TFE") 59 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => txFifo.Count != txFifo.Capacity, name: "TNF") 60 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => rxFifo.Count != 0, name: "RNE") 61 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => rxFifo.Count == rxFifo.Capacity, name: "RFF") 62 .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => txFifo.Count != 0, name: "BSY") //SSI is currently transmitting and/or 63 //receiving a frame or the transmit fifo is not empty. Only the last part is applicable 64 .WithReservedBits(5, 27) 65 }, 66 { (long)Registers.InterruptMask, new DoubleWordRegister(this) 67 .WithFlag(0, out rxFifoOverrunInterruptMask, name: "RORIM") 68 .WithTaggedFlag("RTIM", 1) 69 .WithFlag(2, out rxFifoInterruptMask, name: "RXIM") 70 .WithFlag(3, out txFifoInterruptMask, name: "TXIM") 71 .WithReservedBits(4, 28) 72 .WithWriteCallback((_, __) => Update()) 73 }, 74 { (long)Registers.RawInterruptStatus, new DoubleWordRegister(this) 75 .WithFlag(0, out rxFifoOverrunInterrupt, FieldMode.Read, name: "RORRIS") 76 .WithTaggedFlag("RTRIS", 1) 77 .WithFlag(2, out rxFifoInterrupt, FieldMode.Read, name: "RXRIS") 78 .WithFlag(3, out txFifoInterrupt, FieldMode.Read, name: "TXRIS") 79 .WithReservedBits(4, 28) 80 }, 81 { (long)Registers.MaskedInterruptStatus, new DoubleWordRegister(this) 82 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => rxFifoOverrunInterrupt.Value && rxFifoOverrunInterruptMask.Value, name: "RORMIS") 83 .WithTaggedFlag("RTMIS", 1) 84 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => rxFifoInterrupt.Value && rxFifoInterruptMask.Value, name: "RXMIS") 85 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => txFifoInterrupt.Value && txFifoInterruptMask.Value, name: "TXMIS") 86 .WithReservedBits(4, 28) 87 }, 88 { (long)Registers.InterruptClear, new DoubleWordRegister(this) 89 .WithFlag(0, FieldMode.Read | FieldMode.WriteOneToClear, writeCallback: (_, value) => { 90 if(value) 91 { 92 rxFifoOverrunInterrupt.Value = false; 93 } 94 }) 95 .WithTaggedFlag("RTIC", 1) 96 .WithReservedBits(2, 30) 97 .WithWriteCallback((_, __) => Update()) 98 }, 99 }; 100 registers = new DoubleWordRegisterCollection(this, regs); 101 } 102 ReadDoubleWord(long offset)103 public uint ReadDoubleWord(long offset) 104 { 105 return registers.Read(offset); 106 } 107 WriteDoubleWord(long offset, uint value)108 public void WriteDoubleWord(long offset, uint value) 109 { 110 registers.Write(offset, value); 111 } 112 Reset()113 public override void Reset() 114 { 115 registers.Reset(); 116 rxFifo.Clear(); 117 txFifo.Clear(); 118 IRQ.Unset(); 119 } 120 121 public GPIO IRQ { get; private set; } 122 123 public long Size => 0x1000; 124 EnableTransmitter(bool _, bool enabled)125 private void EnableTransmitter(bool _, bool enabled) 126 { 127 if(enabled && txFifo.Count > 0) 128 { 129 foreach(var value in txFifo.DequeueAll()) 130 { 131 SendByte(value); 132 } 133 Update(); 134 } 135 } 136 SendData(uint value)137 private void SendData(uint value) 138 { 139 var byteValue = (byte)value; 140 if(value != byteValue) 141 { 142 this.Log(LogLevel.Warning, "Trying to send 0x{0:X}, but it doesn't fit in a byte. Will send 0x{1:X} instead", value, byteValue); 143 } 144 if(enabled.Value) 145 { 146 SendByte(byteValue); 147 } 148 else 149 { 150 this.Log(LogLevel.Noisy, "Deferring the transfer of 0x{0:X} as the transmitter is not enabled", byteValue); 151 txFifo.Enqueue(byteValue); 152 } 153 Update(); 154 } 155 SendByte(byte value)156 private void SendByte(byte value) 157 { 158 if(RegisteredPeripheral == null) 159 { 160 this.Log(LogLevel.Warning, "Trying to write 0x{0:X} to a slave peripheral, but nothing is connected"); 161 return; 162 } 163 var response = RegisteredPeripheral.Transmit(value); 164 this.Log(LogLevel.Noisy, "Transmitted deferred data 0x{0:X}, received 0x{1:X}", value, response); 165 if(!rxFifo.Enqueue(response)) 166 { 167 this.Log(LogLevel.Warning, "Receive FIFO overrun"); 168 rxFifoOverrunInterrupt.Value = true; 169 } 170 } 171 Update()172 private void Update() 173 { 174 txFifoInterrupt.Value = txFifo.Count <= txFifo.Capacity / 2; 175 rxFifoInterrupt.Value = rxFifo.Count >= rxFifo.Capacity / 2; 176 //rxFifoOverrunInterrupt is set in `SendData` 177 IRQ.Set((txFifoInterrupt.Value && txFifoInterruptMask.Value) 178 || (rxFifoInterrupt.Value && rxFifoInterruptMask.Value) 179 || (rxFifoOverrunInterrupt.Value && rxFifoOverrunInterruptMask.Value)); 180 } 181 182 private DoubleWordRegisterCollection registers; 183 private CircularBuffer<byte> rxFifo; 184 private CircularBuffer<byte> txFifo; 185 186 private IFlagRegisterField enabled; 187 188 private IFlagRegisterField rxFifoOverrunInterruptMask; 189 private IFlagRegisterField rxFifoInterruptMask; 190 private IFlagRegisterField txFifoInterruptMask; 191 192 private IFlagRegisterField rxFifoOverrunInterrupt; 193 private IFlagRegisterField rxFifoInterrupt; 194 private IFlagRegisterField txFifoInterrupt; 195 196 private const int FifoCapacity = 16; 197 198 public enum Registers 199 { 200 Control0 = 0x0, 201 Control1 = 0x4, 202 Data = 0x8, 203 Status = 0xC, 204 ClockPrescaler = 0x10, 205 InterruptMask = 0x14, 206 RawInterruptStatus = 0x18, 207 MaskedInterruptStatus = 0x1C, 208 InterruptClear = 0x20, 209 DMAControl = 0x24, 210 ClockConfiguration = 0xFC8, 211 } 212 } 213 } 214