1 // 2 // Copyright (c) 2010-2022 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.Core.Structure; 9 using Antmicro.Renode.Peripherals.I2C; 10 using Antmicro.Renode.Peripherals.Sensors; 11 using NUnit.Framework; 12 using I2C = Antmicro.Renode.Peripherals.I2C.OpenTitan_I2C; 13 14 namespace Antmicro.Renode.PeripheralsTests 15 { 16 [TestFixture] 17 public class OpenTitan_I2C_Test 18 { 19 [SetUp] Setup()20 public void Setup() 21 { 22 this.machine = new Machine(); 23 this.sensor1 = new BMP180(); 24 this.sensor2 = new PAC1934(); 25 this.peripheral = new OpenTitan_I2C(machine); 26 machine.SystemBus.Register(peripheral, new Peripherals.Bus.BusRangeRegistration(new Range(0x1000, 0x1000))); 27 peripheral.Register(sensor1, new NumberRegistrationPoint<int>(Sensor1Address)); 28 peripheral.Register(sensor2, new NumberRegistrationPoint<int>(Sensor2Address)); 29 } 30 31 [Test] ShouldPerformSimpleTransaction()32 public void ShouldPerformSimpleTransaction() 33 { 34 EnableHost(); 35 Assert.AreEqual(Sensor1Id, PerformReadFromSlave(Sensor1Address, Sensor1IdOffset), "Incorrect ID for sensor"); 36 } 37 38 [Test] ShouldBeAbleToDoTwoConsecutiveTransmissions()39 public void ShouldBeAbleToDoTwoConsecutiveTransmissions() 40 { 41 EnableHost(); 42 Assert.AreEqual(Sensor1Id, PerformReadFromSlave(Sensor1Address, Sensor1IdOffset), "Incorrect ID for sensor1"); 43 Assert.AreEqual(Sensor2Id, PerformReadFromSlave(Sensor2Address, Sensor2IdOffset), "Incorrect ID for sensor2"); 44 } 45 46 [Test] ShouldNotStartTransactionsUntilHostIsEnabled()47 public void ShouldNotStartTransactionsUntilHostIsEnabled() 48 { 49 Assert.AreEqual(0u, PerformReadFromSlave(Sensor1Address, Sensor1IdOffset), "Read some non-zero data"); 50 // Assert that the fmt queue is not empty 51 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.Status) & 0x04, "Fmt queue empty"); 52 // Assert that the rx queue is empty 53 Assert.AreEqual(RxQueueEmptyMask, ReadFromRegister(I2C.Registers.Status) & RxQueueEmptyMask, "Rx queue not empty"); 54 55 EnableHost(); 56 // Assert that the rx queue is not empty 57 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.Status) & RxQueueEmptyMask, "Rx queue empty"); 58 Assert.AreEqual(Sensor1Id, ReadFromRegister(I2C.Registers.ReadData), "Incorrect data read"); 59 } 60 61 [Test] ShouldSetExceptionOnFmtWatermark()62 public void ShouldSetExceptionOnFmtWatermark() 63 { 64 // Enable the fmt overflow interrupt 65 WriteToRegister(I2C.Registers.InterruptEnable, 0x1); 66 // Set format fmt watermark level to 4 67 WriteToRegister(I2C.Registers.FifoControl, 1 << 5); 68 var command = new I2C.FormatIndicator(data: Sensor1Address, start: true); 69 for(var i = 0; i < 3; i++) 70 { 71 EnqueueCommand(command); 72 } 73 // Interrupt not set yet 74 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.InterruptState), "Expected no interrupts at this point"); 75 EnqueueCommand(command); 76 // Interrupt set 77 Assert.AreEqual(FmtWatermarkInterruptMask, ReadFromRegister(I2C.Registers.InterruptState) & FmtWatermarkInterruptMask, "Interrupt not set"); 78 Assert.AreEqual(true, peripheral.FormatWatermarkIRQ.IsSet, "IRQ not set"); 79 } 80 81 [Test] ShouldSetExceptionOnRxWatermark()82 public void ShouldSetExceptionOnRxWatermark() 83 { 84 // Enable the rx overflow interrupt 85 WriteToRegister(I2C.Registers.InterruptEnable, 0x2); 86 87 EnableHost(); 88 EnqueueCommand(new I2C.FormatIndicator(data: Sensor1Address, start: true)); 89 // Select read address 90 EnqueueCommand(new I2C.FormatIndicator(data: Sensor1IdOffset)); 91 // Interrupt not set yet 92 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.InterruptState) & RxWatermarkInterruptMask, "Expected no interrupt at this point"); 93 EnqueueCommand(new I2C.FormatIndicator(data: 1, read: true, stop: true)); 94 // Interrupt set 95 Assert.AreEqual(RxWatermarkInterruptMask, ReadFromRegister(I2C.Registers.InterruptState) & RxWatermarkInterruptMask, "Interrupt not set"); 96 Assert.AreEqual(true, peripheral.RxWatermarkIRQ.IsSet, "IRQ not set"); 97 } 98 99 [Test] ShouldSetExceptionOnOverflow()100 public void ShouldSetExceptionOnOverflow() 101 { 102 // Enable the fmt overflow interrupt 103 WriteToRegister(I2C.Registers.InterruptEnable, 0x1 << 2); 104 var command = new I2C.FormatIndicator(data: Sensor1Address, start: true); 105 for(var i = 0; i < 64; i++) 106 { 107 EnqueueCommand(command); 108 } 109 // Interrupt not set yet 110 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.InterruptState) & FmtOverflowInterruptMask, "Expected no interrupt at this point"); 111 EnqueueCommand(command); 112 // Interrupt set 113 Assert.AreEqual(FmtOverflowInterruptMask, ReadFromRegister(I2C.Registers.InterruptState) & FmtOverflowInterruptMask, "Interrupt not set"); 114 Assert.AreEqual(true, peripheral.FormatOverflowIRQ.IsSet, "IRQ not set"); 115 } 116 117 [Test] ShouldBeAbleToResetFmtFifo()118 public void ShouldBeAbleToResetFmtFifo() 119 { 120 EnqueueReadFromSlave(Sensor1Address, Sensor1IdOffset); 121 122 // Assert that the format fifo is not empty 123 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.Status) & FmtFifoEmptyMask); 124 // Write one to the FMTRST 125 WriteToRegister(I2C.Registers.FifoControl, 0x01 << 1); 126 // Assert that the format fifo is not empty 127 Assert.AreEqual(FmtFifoEmptyMask, ReadFromRegister(I2C.Registers.Status) & FmtFifoEmptyMask); 128 } 129 130 [Test] ShouldBeAbleToResetRxFifo()131 public void ShouldBeAbleToResetRxFifo() 132 { 133 EnableHost(); 134 EnqueueReadFromSlave(Sensor1Address, Sensor1IdOffset); 135 136 // Assert that the rx queue is not empty 137 Assert.AreEqual(0u, ReadFromRegister(I2C.Registers.Status) & RxQueueEmptyMask, "RxQueue Empty"); 138 // Clear Rx Fifo 139 WriteToRegister(I2C.Registers.FifoControl, 0x01 << 0); 140 Assert.AreEqual(RxQueueEmptyMask, ReadFromRegister(I2C.Registers.Status) & RxQueueEmptyMask); 141 } 142 143 [Test] ShouldNotAllowEnablingBothModesAtTheSameTime()144 public void ShouldNotAllowEnablingBothModesAtTheSameTime() 145 { 146 EnableTarget(); 147 EnableHost(); 148 Assert.AreEqual(1u, ReadFromRegister(I2C.Registers.Control)); 149 } 150 151 [Test] ShouldNotAcceptCommandsWhenInTargetMode()152 public void ShouldNotAcceptCommandsWhenInTargetMode() 153 { 154 EnableTarget(); 155 EnqueueCommand(new I2C.FormatIndicator(data: Sensor1Address, start: true)); 156 Assert.AreEqual(FmtFifoEmptyMask, ReadFromRegister(I2C.Registers.Status) & FmtFifoEmptyMask); 157 } 158 159 [Test] ShouldQueueTransmitBytesWhenInTargetMode()160 public void ShouldQueueTransmitBytesWhenInTargetMode() 161 { 162 EnableTarget(); 163 EnqueueTransmission(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); 164 Assert.AreEqual(9u, GetTxFifoLevel()); 165 } 166 167 [Test] ShouldNotQueueTransmissionWhenInHostMode()168 public void ShouldNotQueueTransmissionWhenInHostMode() 169 { 170 EnableHost(); 171 EnqueueTransmission(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); 172 Assert.AreEqual(0u, GetTxFifoLevel()); 173 } 174 175 [Test] TargetShouldInterpretTransmissionCompleteAsStop()176 public void TargetShouldInterpretTransmissionCompleteAsStop() 177 { 178 EnableTarget(); 179 peripheral.FinishTransmission(); 180 Assert.AreEqual(new I2C.AcquireFormatIndicator(0x0, false, true), 181 I2C.AcquireFormatIndicator.FromRegister(ReadFromRegister(I2C.Registers.AcquiredData)), 182 "Expected stop flag"); 183 } 184 185 [Test] TargetShouldCorrectlyAssignRWflag()186 public void TargetShouldCorrectlyAssignRWflag() 187 { 188 EnableTarget(); 189 var someAddr = 0x7Fu; 190 var readBit = 0x1u; 191 peripheral.Write(new byte[] { (byte)((someAddr << 1) | readBit) }); 192 peripheral.FinishTransmission(); 193 readBit = 0x0u; 194 peripheral.Write(new byte[] { (byte)((someAddr << 1) | readBit) }); 195 peripheral.FinishTransmission(); 196 var acqFormat = I2C.AcquireFormatIndicator.FromRegister(ReadFromRegister(I2C.Registers.AcquiredData)); 197 198 Assert.AreEqual((someAddr << 1) | 1u, acqFormat.Data, "Expected correct data in the 1st paket"); 199 Assert.AreEqual(true, acqFormat.ReadFlag, "Expected correct read flag in the 1st paket"); 200 Assert.AreEqual(true, acqFormat.StartFlag, "Expected correct start flag in the 1st paket"); 201 Assert.AreEqual(false, acqFormat.StopFlag, "Expected correct stop flag in the 1st paket"); 202 203 acqFormat = I2C.AcquireFormatIndicator.FromRegister(ReadFromRegister(I2C.Registers.AcquiredData)); 204 Assert.AreEqual(true, acqFormat.StopFlag, "Expected correct stop flag in the 2nd "); 205 206 acqFormat = I2C.AcquireFormatIndicator.FromRegister(ReadFromRegister(I2C.Registers.AcquiredData)); 207 Assert.AreEqual((someAddr << 1) | 0u, acqFormat.Data, "Expected correct data in the 3rd paket"); 208 Assert.AreEqual(false, acqFormat.ReadFlag, "Expected correct read flag in the 3rd paket"); 209 Assert.AreEqual(true, acqFormat.StartFlag, "Expected correct start flag in the 3rd paket"); 210 Assert.AreEqual(false, acqFormat.StopFlag, "Expected correct stop flag in the 3rd paket"); 211 212 acqFormat = I2C.AcquireFormatIndicator.FromRegister(ReadFromRegister(I2C.Registers.AcquiredData)); 213 Assert.AreEqual(true, acqFormat.StopFlag, "Expected correct stop flag in the 4th packet"); 214 } 215 216 [Test] TargetShouldProperlyHandleRead()217 public void TargetShouldProperlyHandleRead() 218 { 219 EnableTarget(); 220 var data = new byte[] { 0x1, 0x2, 0xFF, 0x3, 0x4, 0xFE }; 221 foreach(var b in data) 222 { 223 WriteToRegister(I2C.Registers.TransmitData, b); 224 } 225 var readData = peripheral.Read(6); 226 227 Assert.AreEqual(6, readData.Length, "Received data length mismatch"); 228 Assert.AreEqual(data, readData, "Received data mismatch"); 229 } 230 231 [Test] TargetShouldNotReturnMoreThanQueued()232 public void TargetShouldNotReturnMoreThanQueued() 233 { 234 EnableTarget(); 235 WriteToRegister(I2C.Registers.TransmitData, 0x1); 236 Assert.AreEqual(1, peripheral.Read(10).Length); 237 } 238 239 [Test] ShouldCorrectlyShowStatusOfTheAcqFifo()240 public void ShouldCorrectlyShowStatusOfTheAcqFifo() 241 { 242 EnableTarget(); 243 Assert.AreEqual(AcqFifoEmptyMask, ReadFromRegister(I2C.Registers.Status) & AcqFifoEmptyMask, "Fifo not empty after init"); 244 for(var x = 0; x < 4; x++) 245 { 246 peripheral.Write(new byte[] { 0x1 }); 247 } 248 Assert.AreEqual(0, ReadFromRegister(I2C.Registers.Status) & AcqFifoEmptyMask, "Fifo empty after peripheral write?"); 249 Assert.AreEqual(4, ((int)ReadFromRegister(I2C.Registers.FifoStatus) >> (int)AcqFifoLevelOffset) & FifoLevelMask, "Wrong fifo level returned"); 250 251 for(var x = 0; x < 60; x++) 252 { 253 peripheral.Write(new byte[] { 0x1 }); 254 } 255 Assert.AreEqual(AcqFifoFullMask, ReadFromRegister(I2C.Registers.Status) & AcqFifoFullMask, "Fifo not full after 64 writes?"); 256 Assert.AreEqual(64, ReadFromRegister(I2C.Registers.FifoStatus) >> (int)AcqFifoLevelOffset, "Wrong fifo level returned"); 257 WriteToRegister(I2C.Registers.FifoControl, AcqFifoResetMask); 258 Assert.AreEqual(AcqFifoEmptyMask, ReadFromRegister(I2C.Registers.Status) & AcqFifoEmptyMask, "Fifo not empty after reset"); 259 } 260 261 [Test] ShouldCorrectlyShowStatusOfTheTxFifo()262 public void ShouldCorrectlyShowStatusOfTheTxFifo() 263 { 264 EnableTarget(); 265 Assert.AreEqual(TxFifoEmptyMask, ReadFromRegister(I2C.Registers.Status) & TxFifoEmptyMask, "Fifo not empty after init"); 266 for(var x = 0; x < 4; x++) 267 { 268 WriteToRegister(I2C.Registers.TransmitData, 0x1); 269 } 270 Assert.AreEqual(0, ReadFromRegister(I2C.Registers.Status) & TxFifoEmptyMask, "Fifo empty?"); 271 Assert.AreEqual(4, ReadFromRegister(I2C.Registers.FifoStatus) >> 8, "Wrong fifo level returned"); 272 273 for(var x = 0; x < 60; x++) 274 { 275 WriteToRegister(I2C.Registers.TransmitData, 0x1); 276 } 277 Assert.AreEqual(TxFifoFullMask, ReadFromRegister(I2C.Registers.Status) & TxFifoFullMask, "Fifo not full after 64 writes?"); 278 Assert.AreEqual(64, ReadFromRegister(I2C.Registers.FifoStatus) >> (int)TxFifoLevelOffset, "Wrong fifo level returned"); 279 WriteToRegister(I2C.Registers.FifoControl, TxFifoResetMask); 280 Assert.AreEqual(TxFifoEmptyMask, ReadFromRegister(I2C.Registers.Status) & TxFifoEmptyMask, "Fifo not empty after reset"); 281 } 282 PerformReadFromSlave(byte address, byte offset)283 private byte PerformReadFromSlave(byte address, byte offset) 284 { 285 EnqueueReadFromSlave(address, offset); 286 return (byte)ReadFromRegister(I2C.Registers.ReadData); 287 } 288 EnqueueReadFromSlave(byte address, byte offset)289 private void EnqueueReadFromSlave(byte address, byte offset) 290 { 291 // Select slave address 292 EnqueueCommand(new I2C.FormatIndicator(data: address, start: true)); 293 // Select read address 294 EnqueueCommand(new I2C.FormatIndicator(data: offset)); 295 // Read one byte from selected address 296 EnqueueCommand(new I2C.FormatIndicator(data: 1, read: true, stop: true)); 297 } 298 EnableHost()299 private void EnableHost() 300 { 301 WriteToRegister(I2C.Registers.Control, 0x1); 302 } 303 EnableTarget()304 private void EnableTarget() 305 { 306 WriteToRegister(I2C.Registers.Control, 0x2); 307 } 308 EnqueueTransmission(byte[] bytes)309 private void EnqueueTransmission(byte[] bytes) 310 { 311 foreach(var b in bytes) 312 { 313 WriteToRegister(I2C.Registers.TransmitData, b); 314 } 315 } 316 EnqueueCommand(I2C.FormatIndicator command)317 private void EnqueueCommand(I2C.FormatIndicator command) 318 { 319 WriteToRegister(I2C.Registers.FormatData, command.ToRegisterFormat()); 320 } 321 WriteToRegister(I2C.Registers register, uint value)322 private void WriteToRegister(I2C.Registers register, uint value) 323 { 324 peripheral.WriteDoubleWord((long)register, value); 325 } 326 ReadFromRegister(I2C.Registers register)327 private uint ReadFromRegister(I2C.Registers register) 328 { 329 return peripheral.ReadDoubleWord((long)register); 330 } 331 GetTxFifoLevel()332 private uint GetTxFifoLevel() 333 { 334 return (ReadFromRegister(I2C.Registers.FifoStatus) >> 8) & 0x7F; 335 } 336 337 private IMachine machine; 338 private II2CPeripheral sensor1; 339 private II2CPeripheral sensor2; 340 private OpenTitan_I2C peripheral; 341 342 private const byte Sensor1Address = 0x77; 343 private const byte Sensor1Id = 0x55; 344 private const byte Sensor1IdOffset = 0xD0; 345 private const byte Sensor2Address = 0x78; 346 private const byte Sensor2Id = 0x5B; 347 private const byte Sensor2IdOffset = 0xFD; 348 349 private const uint FifoLevelMask = 0x7F; 350 private const uint AcqFifoLevelOffset = 24; 351 private const uint TxFifoLevelOffset = 8; 352 353 private const uint AcqFifoResetMask = 0x80; 354 private const uint TxFifoResetMask = 0x100; 355 356 private const uint AcqFifoEmptyMask = 0x200; 357 private const uint AcqFifoFullMask = 0x80; 358 private const uint FmtFifoEmptyMask = 0x04; 359 private const uint FmtOverflowInterruptMask = 0x4; 360 private const uint FmtWatermarkInterruptMask = 0x1; 361 private const uint RxQueueEmptyMask = 0x20; 362 private const uint RxWatermarkInterruptMask = 0x2; 363 private const uint TxFifoEmptyMask = 0x100; 364 private const uint TxFifoFullMask = 0x40; 365 } 366 } 367