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 8 using System; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Utilities; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.Memory; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Core.Structure.Registers; 15 16 namespace Antmicro.Renode.Peripherals.SPI 17 { 18 // This peripheral only implements the generic operation mode 19 [AllowedTranslations(AllowedTranslation.DoubleWordToByte)] 20 public class OpenTitan_SpiDevice : BasicDoubleWordPeripheral, IBytePeripheral, ISPIPeripheral, IKnownSize 21 { OpenTitan_SpiDevice(IMachine machine)22 public OpenTitan_SpiDevice(IMachine machine) : base(machine) 23 { 24 underlyingSramMemory = new ArrayMemory(BufferWindowSizeInDoublewords * 4); 25 26 DefineRegisters(); 27 rxFifo = new SRAMCircularFifoRange(0u, InitialRxFifoBoundary, underlyingSramMemory); 28 txFifo = new SRAMCircularFifoRange(InitialRxFifoBoundary + 1, InitialTxFifoBoundary, underlyingSramMemory); 29 30 GenericRxFull = new GPIO(); 31 GenericRxWatermark = new GPIO(); 32 GenericTxWatermark = new GPIO(); 33 GenericRxError = new GPIO(); 34 GenericRxOverflow = new GPIO(); 35 GenericTxUnderflow = new GPIO(); 36 UploadCmdFifoNotEmpty = new GPIO(); 37 UploadPayloadNotEmpty = new GPIO(); 38 UploadPayloadOverflow = new GPIO(); 39 ReadBufferWatermark = new GPIO(); 40 ReadBufferFlip = new GPIO(); 41 TPMHeaderNotEmpty = new GPIO(); 42 43 FatalAlert = new GPIO(); 44 Reset(); 45 } 46 47 // Byte accesses are needed for the fifo SRAM interface WriteByte(long offset, byte value)48 public void WriteByte(long offset, byte value) 49 { 50 if(offset >= (long)Registers.Buffer) 51 { 52 var bufferOffset = offset - (long)Registers.Buffer; 53 if(IsOffsetInRxFifoRange(bufferOffset)) 54 { 55 this.Log(LogLevel.Debug, "Accesses the Rx fifo contents directly using the direct memory write"); 56 } 57 // We may use direct sram memory write as the driver is responsible to handle the pointers in that case 58 underlyingSramMemory.WriteByte(bufferOffset, value); 59 } 60 else 61 { 62 this.Log(LogLevel.Error, "Byte interface should only be used on the buffer. Ignoring write of value 0x{0:X}, to offset 0x{1:X}", value, offset); 63 } 64 } 65 ReadByte(long offset)66 public byte ReadByte(long offset) 67 { 68 if(offset >= (long)Registers.Buffer) 69 { 70 var bufferOffset = offset - (long)Registers.Buffer; 71 return underlyingSramMemory.ReadByte(bufferOffset); 72 } 73 else 74 { 75 this.Log(LogLevel.Error, "Byte interface should only be used on the buffer. Ignoring read from offset 0x{1:X}", offset); 76 return 0; 77 } 78 } 79 WriteDoubleWord(long offset, uint value)80 public override void WriteDoubleWord(long offset, uint value) 81 { 82 if(offset >= (long)Registers.Buffer) 83 { 84 // Access to the sram buffer 85 var bufferOffset = offset - (long)Registers.Buffer; 86 if(IsOffsetInTxFifoRange(bufferOffset)) 87 { 88 var dataInBytes = BitHelper.GetBytesFromValue(value, sizeof(uint)); 89 if(!txOrderLsbFirst.Value) 90 { 91 Array.Reverse(dataInBytes); 92 } 93 foreach(var b in dataInBytes) 94 { 95 var txFifoStatus = txFifo.WriteByte(b); 96 } 97 } 98 else 99 { 100 underlyingSramMemory.WriteDoubleWord(offset - (long)Registers.Buffer, value); 101 } 102 } 103 else 104 { 105 base.WriteDoubleWord(offset, value); 106 } 107 } 108 ReadDoubleWord(long offset)109 public override uint ReadDoubleWord(long offset) 110 { 111 if(offset >= (long)Registers.Buffer) 112 { 113 // Acces to the sram buffer 114 this.Log(LogLevel.Debug, "Reading from sram memory; value at addr {0}", offset - 0x1000); 115 var readValue = underlyingSramMemory.ReadDoubleWord(offset - (long)Registers.Buffer); 116 if(IsOffsetInRxFifoRange(offset)) 117 { 118 readValue = Misc.ByteArrayRead(0, BitHelper.GetBytesFromValue(readValue, sizeof(uint))); 119 } 120 return readValue; 121 } 122 else 123 { 124 return base.ReadDoubleWord(offset); 125 } 126 } 127 Reset()128 public override void Reset() 129 { 130 base.Reset(); 131 FatalAlert.Unset(); 132 } 133 Transmit(byte data)134 public byte Transmit(byte data) 135 { 136 byte output = 0; 137 SRAMCircularFifoRange.FifoStatus rxFifoStatus, txFifoStatus = SRAMCircularFifoRange.FifoStatus.Empty; 138 139 if(txFifo.CurrentDepth > 0) 140 { 141 txFifoStatus = txFifo.ReadByte(out output); 142 143 if(txFifo.CurrentDepth < txFifoWatermarkLevel.Value) 144 { 145 txWatermarkInterruptState.Value = true; 146 } 147 } 148 else 149 { 150 txFifoStatus = SRAMCircularFifoRange.FifoStatus.Underflow; 151 } 152 153 rxFifoStatus = rxFifo.WriteByte(data); 154 155 if(rxFifo.CurrentDepth > rxFifoWatermarkLevel.Value) 156 { 157 rxWatermarkInterruptState.Value = true; 158 } 159 160 HandleFifoStatusesAndUpdateInterrupts(rxFifoStatus, txFifoStatus); 161 162 return output; 163 } 164 IsOffsetInRxFifoRange(long bufferOffset)165 private bool IsOffsetInRxFifoRange(long bufferOffset) 166 { 167 return (bufferOffset >= rxFifo.Base) && (bufferOffset <= rxFifo.Limit); 168 } 169 IsOffsetInTxFifoRange(long offset)170 private bool IsOffsetInTxFifoRange(long offset) 171 { 172 return (offset >= txFifo.Base) && (offset <= txFifo.Limit); 173 } 174 175 /* Translates the fifo states into interrupts */ HandleFifoStatusesAndUpdateInterrupts(SRAMCircularFifoRange.FifoStatus rxFifoStatus, SRAMCircularFifoRange.FifoStatus txFifoStatus)176 private void HandleFifoStatusesAndUpdateInterrupts(SRAMCircularFifoRange.FifoStatus rxFifoStatus, SRAMCircularFifoRange.FifoStatus txFifoStatus) 177 { 178 switch(rxFifoStatus) 179 { 180 case SRAMCircularFifoRange.FifoStatus.Overflow: 181 rxOverflowInterruptState.Value = true; 182 break; 183 case SRAMCircularFifoRange.FifoStatus.Full: 184 rxFullInterruptState.Value = true; 185 break; 186 default: 187 break; 188 } 189 switch(txFifoStatus) 190 { 191 case SRAMCircularFifoRange.FifoStatus.Underflow: 192 txUnderflowInterruptState.Value = true; 193 break; 194 default: 195 break; 196 } 197 UpdateInterrupts(); 198 } 199 FinishTransmission()200 public void FinishTransmission() 201 { 202 // Intentionaly left blank 203 } 204 205 // Common Interrupt Offsets 206 public GPIO GenericRxFull { get; } 207 public GPIO GenericRxWatermark { get; } 208 public GPIO GenericTxWatermark { get; } 209 public GPIO GenericRxError { get; } 210 public GPIO GenericRxOverflow { get; } 211 public GPIO GenericTxUnderflow { get; } 212 public GPIO UploadCmdFifoNotEmpty { get; } 213 public GPIO UploadPayloadNotEmpty { get; } 214 public GPIO UploadPayloadOverflow { get; } 215 public GPIO ReadBufferWatermark { get; } 216 public GPIO ReadBufferFlip { get; } 217 public GPIO TPMHeaderNotEmpty { get; } 218 public GPIO FatalAlert { get; private set; } 219 220 public long Size => 0x2000; 221 DefineRegisters()222 private void DefineRegisters() 223 { 224 Registers.InterruptState.Define(this) 225 .WithFlag(0, out rxFullInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "generic_rx_full") 226 .WithFlag(1, out rxWatermarkInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "generic_rx_watermark") 227 .WithFlag(2, out txWatermarkInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "generic_tx_watermark") 228 .WithFlag(3, out rxErrorInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "generic_rx_error") 229 .WithFlag(4, out rxOverflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "generic_rx_overflow") 230 .WithFlag(5, out txUnderflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "generic_tx_underflow") 231 .WithFlag(6, out cmdfifoNotEmptyInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "upload_cmdfifo_not_empty") 232 .WithFlag(7, out payloadNotEmptyInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "upload_payload_not_empty") 233 .WithFlag(8, out payloadOverflowInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "upload_payload_overflow") 234 .WithFlag(9, out readbufWatermarkInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "readbuf_watermark") 235 .WithFlag(10, out readbufFlipInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "readbuf_flip") 236 .WithFlag(11, out tpmHeaderNotEmptyInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "tpm_header_not_empty") 237 .WithReservedBits(12, 20) 238 .WithWriteCallback((_, __) => UpdateInterrupts()); 239 240 Registers.InterruptEnable.Define(this) 241 .WithFlag(0, out rxFullInterruptEnable, name: "generic_rx_full") 242 .WithFlag(1, out rxWatermarkInterruptEnable, name: "generic_rx_watermark") 243 .WithFlag(2, out txWatermarkInterruptEnable, name: "generic_tx_watermark") 244 .WithFlag(3, out rxErrorInterruptEnable, name: "generic_rx_error") 245 .WithFlag(4, out rxOverflowInterruptEnable, name: "generic_rx_overflow") 246 .WithFlag(5, out txUnderflowInterruptEnable, name: "generic_tx_underflow") 247 .WithFlag(6, out cmdfifoNotEmptyInterruptEnable, name: "upload_cmdfifo_not_empty") 248 .WithFlag(7, out payloadNotEmptyInterruptEnable, name: "upload_payload_not_empty") 249 .WithFlag(8, out payloadOverflowInterruptEnable, name: "upload_payload_overflow") 250 .WithFlag(9, out readbufWatermarkInterruptEnable, name: "readbuf_watermark") 251 .WithFlag(10, out readbufFlipInterruptEnable, name: "readbuf_flip") 252 .WithFlag(11, out tpmHeaderNotEmptyInterruptEnable, name: "tpm_header_not_empty") 253 .WithReservedBits(12, 20) 254 .WithWriteCallback((_, __) => UpdateInterrupts()); 255 256 Registers.InterruptTest.Define(this) 257 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { rxFullInterruptState.Value = val; }, name: "generic_rx_full") 258 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { rxWatermarkInterruptState.Value = val; }, name: "generic_rx_watermark") 259 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { txWatermarkInterruptState.Value = val; }, name: "generic_tx_watermark") 260 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { rxErrorInterruptState.Value = val; }, name: "generic_rx_error") 261 .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { rxOverflowInterruptState.Value = val; }, name: "generic_rx_overflow") 262 .WithFlag(5, FieldMode.Write, writeCallback: (_, val) => { txUnderflowInterruptState.Value = val; }, name: "generic_tx_underflow") 263 .WithFlag(6, FieldMode.Write, writeCallback: (_, val) => { cmdfifoNotEmptyInterruptState.Value = val; }, name: "upload_cmdfifo_not_empty") 264 .WithFlag(7, FieldMode.Write, writeCallback: (_, val) => { payloadNotEmptyInterruptState.Value = val; }, name: "upload_payload_not_empty") 265 .WithFlag(8, FieldMode.Write, writeCallback: (_, val) => { payloadOverflowInterruptState.Value = val; }, name: "upload_payload_overflow") 266 .WithFlag(9, FieldMode.Write, writeCallback: (_, val) => { readbufWatermarkInterruptState.Value = val; }, name: "readbuf_watermark") 267 .WithFlag(10, FieldMode.Write, writeCallback: (_, val) => { readbufFlipInterruptState.Value = val; }, name: "readbuf_flip") 268 .WithFlag(11, FieldMode.Write, writeCallback: (_, val) => { tpmHeaderNotEmptyInterruptState.Value = val; }, name: "tpm_header_not_empty") 269 .WithReservedBits(12, 20) 270 .WithWriteCallback((_, val) => { if(val != 0) UpdateInterrupts(); }); 271 272 Registers.AlertTest.Define(this) 273 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_fault") 274 .WithReservedBits(1, 31); 275 276 Registers.Control.Define(this, 0x80000010) 277 .WithFlag(0, name: "ABORT") 278 .WithReservedBits(1, 3) 279 .WithEnumField<DoubleWordRegister, DeviceMode>(4, 2, out mode, 280 writeCallback: (_, val) => 281 { 282 if(val != DeviceMode.Fw) 283 { 284 this.Log(LogLevel.Error, "{0} operation mode is not implemented. Setting mode back to FwMode", val); 285 mode.Value = DeviceMode.Fw; 286 } 287 }, name: "MODE") 288 .WithReservedBits(6, 9) 289 .WithFlag(16, writeCallback: (_, val) => { if(val) txFifo.ResetPointers(); }, name: "rst_txfifo") 290 .WithFlag(17, writeCallback: (_, val) => { if(val) rxFifo.ResetPointers(); }, name: "rst_rxfifo") 291 .WithReservedBits(18, 13) 292 .WithTaggedFlag("sram_clk_en", 31); 293 294 Registers.Configuration.Define(this, 0x7f00) 295 .WithTaggedFlag("CPOL", 0) 296 .WithTaggedFlag("CPHA", 1) 297 .WithFlag(2, out txOrderLsbFirst, name:"tx_order") 298 .WithFlag(3, out rxOrderLsbFirst, name:"rx_order") 299 .WithReservedBits(4, 4) 300 .WithTag("timer_v", 8, 8) 301 .WithTaggedFlag("addr_4b_en", 16) 302 .WithTaggedFlag("mailbox_en", 24) 303 .WithReservedBits(25, 7); 304 305 Registers.FifoLevel.Define(this, 0x80) 306 // Despite the misleading name this register holds the watermark levels - at least thats what the spec suggests 307 .WithValueField(0, 16, out rxFifoWatermarkLevel, name: "rxlvl") // "If the RX SRAM FIFO level exceeds this value, it triggers interrupt." 308 .WithValueField(16, 16, out txFifoWatermarkLevel, name: "txlvl"); // "If the TX SRAM FIFO level drops below this value, it triggers interrupt." 309 310 Registers.AsyncFifoLevel.Define(this) 311 .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: _ => rxFifo.CurrentDepth, name: "rxlvl") 312 .WithValueField(16, 8, FieldMode.Read, valueProviderCallback: _ => txFifo.CurrentDepth, name: "txlvl") 313 .WithReservedBits(24, 8); 314 315 Registers.SPIDevicestatus.Define(this, 0x3a) 316 .WithFlag(0, FieldMode.Read, valueProviderCallback : _ => rxFifo.IsFull, name: "rxf_full") 317 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => rxFifo.IsEmpty, name: "rxf_empty") 318 .WithFlag(2, FieldMode.Read, valueProviderCallback : _ => txFifo.IsFull, name: "txf_full") 319 .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => txFifo.IsEmpty, name: "txf_empty") 320 .WithFlag(4, FieldMode.Read, name: "abort_done") 321 .WithFlag(5, FieldMode.Read, name: "csb") 322 .WithReservedBits(6, 26); 323 324 Registers.ReceiverFifoSramPointers.Define(this) 325 .WithValueField(0, 16, valueProviderCallback: _ => rxFifo.ReadPointerWithPhaseBit, changeCallback: (_, val) => 326 { 327 this.Log(LogLevel.Debug, "Setting the read pointer to {0:x}", val); 328 if(rxFifo.TrySetReadPointer(val)) 329 { 330 this.Log(LogLevel.Error, "Pointer outside of the range. This will be ignored"); 331 } 332 }, name: "RPTR") 333 .WithValueField(16, 16, FieldMode.Read, valueProviderCallback: _ => rxFifo.WritePointerWithPhaseBit, name: "WPTR"); 334 335 Registers.TransmitterFifoSramPointers.Define(this) 336 .WithValueField(0, 16, FieldMode.Read, valueProviderCallback: _ => txFifo.ReadPointerWithPhaseBit, name: "RPTR") 337 .WithValueField(16, 16, valueProviderCallback: _ => txFifo.WritePointerWithPhaseBit, changeCallback: (_, val) => 338 { 339 this.Log(LogLevel.Debug, "Setting the write pointer to {0:x}", val); 340 if(txFifo.TrySetWritePointer(val)) 341 { 342 this.Log(LogLevel.Error, "Pointer outside of the range. This will be ignored"); 343 } 344 }, name: "WPTR"); 345 346 Registers.ReceiverFifoSramAddresses.Define(this, 0x1fc0000) 347 .WithValueField(0, 16, out rxFifoBase, name: "base") 348 .WithValueField(16, 16, out rxFifoLimit, name: "limit") 349 .WithWriteCallback((_, __) => 350 { 351 if(!rxFifo.TryUpdateParameters((uint)rxFifoBase.Value, (uint)rxFifoLimit.Value)) 352 { 353 this.Log(LogLevel.Error, "Parameters were rejected as an invalid range"); 354 } 355 }); 356 357 Registers.TransmitterFifoSramAddresses.Define(this, 0x3fc0200) 358 .WithValueField(0, 16, out txFifoBase, name: "base") 359 .WithValueField(16, 16, out txFifoLimit, name: "limit") 360 .WithWriteCallback((_, __) => 361 { 362 if(!txFifo.TryUpdateParameters((uint)txFifoBase.Value, (uint)txFifoLimit.Value)) 363 { 364 this.Log(LogLevel.Error, "Parameters were rejected as an invalid range"); 365 } 366 }); 367 368 Registers.InterceptEnable.Define(this) 369 .WithTaggedFlag("status", 0) 370 .WithTaggedFlag("jedec", 1) 371 .WithTaggedFlag("sfdp", 2) 372 .WithTaggedFlag("mbx", 3) 373 .WithReservedBits(4, 28); 374 375 Registers.LastReadAddress.Define(this) 376 .WithTag("addr", 0, 32); 377 378 Registers.FlashStatus.Define(this) 379 .WithTaggedFlag("busy", 0) 380 .WithTag("status", 1, 23) 381 .WithReservedBits(24, 8); 382 383 Registers.JedecCc.Define(this, 0x7f) 384 .WithTag("cc", 0, 8) 385 .WithTag("num_cc", 8, 8) 386 .WithReservedBits(16, 16); 387 388 Registers.JedecId.Define(this) 389 .WithTag("id", 0, 16) 390 .WithTag("mf", 16, 8) 391 .WithReservedBits(24, 8); 392 393 Registers.ReadThreshold.Define(this) 394 .WithTag("threshold", 0, 10) 395 .WithReservedBits(10, 22); 396 397 Registers.MailboxAddress.Define(this) 398 .WithTag("addr", 0, 32); 399 400 Registers.UploadStatus.Define(this) 401 .WithTag("cmdfifo_depth", 0, 5) 402 .WithTaggedFlag("cmdfifo_notempty", 7) 403 .WithTag("addrfifo_depth", 8, 5) 404 .WithTaggedFlag("addrfifo_notempty", 5) 405 .WithReservedBits(16, 16); 406 407 Registers.UploadStatus2.Define(this) 408 .WithTag("payload_depth", 0, 9) 409 .WithTag("payload_start_idx", 16, 8) 410 .WithReservedBits(24, 8); 411 412 Registers.UploadCmdFifo.Define(this) 413 .WithTag("data", 0, 8) 414 .WithReservedBits(8, 24); 415 416 Registers.UploadAddrFifo.Define(this) 417 .WithTag("data", 0, 32); 418 419 Registers.CommandFilter.DefineMany(this, SpiDevicesCount, (register, idx) => 420 { 421 register 422 .WithTaggedFlag($"filter_{0 + 32 * idx}", 0) 423 .WithTaggedFlag($"filter_{1 + 32 * idx}", 1) 424 .WithTaggedFlag($"filter_{2 + 32 * idx}", 2) 425 .WithTaggedFlag($"filter_{3 + 32 * idx}", 3) 426 .WithTaggedFlag($"filter_{4 + 32 * idx}", 4) 427 .WithTaggedFlag($"filter_{5 + 32 * idx}", 5) 428 .WithTaggedFlag($"filter_{6 + 32 * idx}", 6) 429 .WithTaggedFlag($"filter_{7 + 32 * idx}", 7) 430 .WithTaggedFlag($"filter_{8 + 32 * idx}", 8) 431 .WithTaggedFlag($"filter_{9 + 32 * idx}", 9) 432 .WithTaggedFlag($"filter_{10 + 32 * idx}", 10) 433 .WithTaggedFlag($"filter_{11 + 32 * idx}", 11) 434 .WithTaggedFlag($"filter_{12 + 32 * idx}", 12) 435 .WithTaggedFlag($"filter_{13 + 32 * idx}", 13) 436 .WithTaggedFlag($"filter_{14 + 32 * idx}", 14) 437 .WithTaggedFlag($"filter_{15 + 32 * idx}", 15) 438 .WithTaggedFlag($"filter_{16 + 32 * idx}", 16) 439 .WithTaggedFlag($"filter_{17 + 32 * idx}", 17) 440 .WithTaggedFlag($"filter_{18 + 32 * idx}", 18) 441 .WithTaggedFlag($"filter_{19 + 32 * idx}", 19) 442 .WithTaggedFlag($"filter_{20 + 32 * idx}", 20) 443 .WithTaggedFlag($"filter_{21 + 32 * idx}", 21) 444 .WithTaggedFlag($"filter_{22 + 32 * idx}", 22) 445 .WithTaggedFlag($"filter_{23 + 32 * idx}", 23) 446 .WithTaggedFlag($"filter_{24 + 32 * idx}", 24) 447 .WithTaggedFlag($"filter_{25 + 32 * idx}", 25) 448 .WithTaggedFlag($"filter_{26 + 32 * idx}", 26) 449 .WithTaggedFlag($"filter_{27 + 32 * idx}", 27) 450 .WithTaggedFlag($"filter_{28 + 32 * idx}", 28) 451 .WithTaggedFlag($"filter_{29 + 32 * idx}", 29) 452 .WithTaggedFlag($"filter_{30 + 32 * idx}", 30) 453 .WithTaggedFlag($"filter_{31 + 32 * idx}", 31); 454 }); 455 456 Registers.AddressSwapMask.Define(this) 457 .WithTag("mask", 0, 32); 458 459 Registers.AddressSwapData.Define(this) 460 .WithTag("data", 0, 32); 461 462 Registers.PayloadSwapMask.Define(this) 463 .WithTag("mask", 0, 32); 464 465 Registers.PayloadSwapData.Define(this) 466 .WithTag("data", 0, 32); 467 468 Registers.CommandInfo.DefineMany(this, DeviceCmdInfoCount, (register, idx) => 469 { 470 register 471 .WithTag("opcode_{idx}", 0, 8) 472 .WithTag("addr_mode_{idx}", 8, 2) 473 .WithTaggedFlag($"addr_swap_en_{idx}", 10) 474 .WithTaggedFlag($"mbyte_en_{idx}", 11) 475 .WithTag("dummy_size_{idx}", 12, 3) 476 .WithTaggedFlag($"dummy_en_{idx}", 15) 477 .WithTag("payload_en_{idx}", 16, 4) 478 .WithTaggedFlag($"payload_dir_{idx}", 20) 479 .WithTaggedFlag($"payload_swap_en_{idx}", 21) 480 .WithReservedBits(22, 2) 481 .WithTaggedFlag($"upload_{idx}", 24) 482 .WithTaggedFlag($"busy_{idx}", 25) 483 .WithReservedBits(26, 5) 484 .WithTaggedFlag($"valid_{idx}", 31); 485 }); 486 487 Registers.CommandInfoEn4b.Define(this) 488 .WithTag("opcode", 0, 8) 489 .WithTaggedFlag("valid", 31); 490 491 Registers.OpcodeForEX4B.Define(this) 492 .WithTag("opcode", 0, 8) 493 .WithTaggedFlag("valid", 31); 494 495 Registers.OpcodeforWriteEnable.Define(this) 496 .WithTag("opcode", 0, 8) 497 .WithTaggedFlag("valid", 31); 498 499 Registers.OpcodeForWriteDisable.Define(this) 500 .WithTag("opcode", 0, 8) 501 .WithTaggedFlag("valid", 31); 502 503 // TPM capabilities not implemented 504 Registers.TPMCapability.Define(this, 0x20100) 505 .WithTag("rev", 0, 8) 506 .WithTaggedFlag("locality", 8) 507 .WithTag("max_xfer_size", 16, 3) 508 .WithReservedBits(19, 13); 509 510 Registers.TPMConfig.Define(this) 511 .WithTaggedFlag("en", 0) 512 .WithTaggedFlag("tpm_mode", 1) 513 .WithTaggedFlag("hw_reg_dis", 2) 514 .WithTaggedFlag("tpm_reg_chk_dis", 3) 515 .WithTaggedFlag("invalid_locality", 4) 516 .WithReservedBits(5, 27); 517 518 Registers.TPMStatus.Define(this) 519 .WithTaggedFlag("cmdaddr_notempty", 0) 520 .WithTaggedFlag("rdfifo_notempty", 1) 521 .WithTag("rdfifo_depth", 4, 3) 522 .WithTag("wrfifo_depth", 8, 3) 523 .WithReservedBits(11, 21); 524 525 Registers.TPMAccess0.Define(this) 526 .WithTag("access_0", 0, 8) 527 .WithTag("access_1", 8, 8) 528 .WithTag("access_2", 16, 8) 529 .WithTag("access_3", 24, 8); 530 531 Registers.TPMAccess1.Define(this) 532 .WithTag("access_4", 0, 8) 533 .WithReservedBits(8, 24); 534 535 Registers.TPMSts.Define(this) 536 .WithTag("sts", 0, 32); 537 538 Registers.TPMIntfCapability.Define(this) 539 .WithTag("intf_capability", 0, 32); 540 541 Registers.TPMIntCapability.Define(this) 542 .WithTag("int_enable", 0, 32); 543 544 Registers.TPMIntVector.Define(this) 545 .WithTag("int_vector", 0, 8) 546 .WithReservedBits(8, 24); 547 548 Registers.TPMIntStatus.Define(this) 549 .WithTag("int_status", 0, 32); 550 551 Registers.TPMDidVid.Define(this) 552 .WithTag("vid", 0, 16) 553 .WithTag("did", 16, 16); 554 555 Registers.TPMRid.Define(this) 556 .WithTag("rid", 0, 8) 557 .WithReservedBits(8, 24); 558 559 Registers.TPMCommandAndAddressBuffer.Define(this) 560 .WithTag("addr", 0, 24) 561 .WithTag("cmd", 24, 8); 562 563 Registers.TPMReadFifo.Define(this) 564 .WithTag("value", 0, 8) 565 .WithReservedBits(8, 24); 566 567 Registers.TPMWriteFifo.Define(this) 568 .WithTag("value", 0, 8) 569 .WithReservedBits(8, 24); 570 571 Registers.Buffer.DefineMany(this, BufferWindowSizeInDoublewords, (register, idx) => 572 { 573 // This range is handled by the read functions 574 register.WithTag($"SPIinternalbuffer{idx}", 0, 3); 575 }); 576 } 577 UpdateInterrupts()578 private void UpdateInterrupts() 579 { 580 GenericRxFull.Set(rxFullInterruptState.Value && rxFullInterruptEnable.Value); 581 GenericRxWatermark.Set(rxWatermarkInterruptState.Value && rxWatermarkInterruptEnable.Value); 582 GenericTxWatermark.Set(txWatermarkInterruptState.Value && txWatermarkInterruptEnable.Value); 583 GenericRxOverflow.Set(rxOverflowInterruptState.Value && rxOverflowInterruptEnable.Value); 584 GenericTxUnderflow.Set(txUnderflowInterruptState.Value && txUnderflowInterruptEnable.Value); 585 // Below interrupts are not implemented and are here just for the interrupt test sake 586 GenericRxError.Set(rxErrorInterruptState.Value && rxErrorInterruptEnable.Value); 587 UploadCmdFifoNotEmpty.Set(cmdfifoNotEmptyInterruptState.Value && cmdfifoNotEmptyInterruptEnable.Value); 588 UploadPayloadNotEmpty.Set(payloadNotEmptyInterruptState.Value && payloadNotEmptyInterruptEnable.Value); 589 UploadPayloadOverflow.Set(payloadOverflowInterruptState.Value && payloadOverflowInterruptEnable.Value); 590 ReadBufferWatermark.Set(readbufWatermarkInterruptState.Value && readbufWatermarkInterruptEnable.Value); 591 ReadBufferFlip.Set(readbufFlipInterruptState.Value && readbufFlipInterruptEnable.Value); 592 TPMHeaderNotEmpty.Set(tpmHeaderNotEmptyInterruptState.Value && tpmHeaderNotEmptyInterruptEnable.Value); 593 } 594 595 // Sram Entries. Word size is 32bit width. 596 private const uint BufferWindowSizeInDoublewords = 1024; 597 private const uint InitialRxFifoBoundary = 2047; 598 private const uint InitialTxFifoBoundary = 4095; 599 600 // Define the number of Command Info slots. 601 private const uint DeviceCmdInfoCount = 24; 602 603 // Define the number of SPI_DEVICE 604 private const uint SpiDevicesCount = 8; 605 606 // The number of locality TPM module supports. 607 private const uint SpiDeviceNumLocality = 5; 608 609 private IFlagRegisterField rxFullInterruptState; 610 private IFlagRegisterField rxWatermarkInterruptState; 611 private IFlagRegisterField txWatermarkInterruptState; 612 private IFlagRegisterField rxErrorInterruptState; 613 private IFlagRegisterField rxOverflowInterruptState; 614 private IFlagRegisterField txUnderflowInterruptState; 615 private IFlagRegisterField cmdfifoNotEmptyInterruptState; 616 private IFlagRegisterField payloadNotEmptyInterruptState; 617 private IFlagRegisterField payloadOverflowInterruptState; 618 private IFlagRegisterField readbufWatermarkInterruptState; 619 private IFlagRegisterField readbufFlipInterruptState; 620 private IFlagRegisterField tpmHeaderNotEmptyInterruptState; 621 private IFlagRegisterField rxFullInterruptEnable; 622 private IFlagRegisterField rxWatermarkInterruptEnable; 623 private IFlagRegisterField txWatermarkInterruptEnable; 624 private IFlagRegisterField rxErrorInterruptEnable; 625 private IFlagRegisterField rxOverflowInterruptEnable; 626 private IFlagRegisterField txUnderflowInterruptEnable; 627 private IFlagRegisterField cmdfifoNotEmptyInterruptEnable; 628 private IFlagRegisterField payloadNotEmptyInterruptEnable; 629 private IFlagRegisterField payloadOverflowInterruptEnable; 630 private IFlagRegisterField readbufWatermarkInterruptEnable; 631 private IFlagRegisterField readbufFlipInterruptEnable; 632 private IFlagRegisterField tpmHeaderNotEmptyInterruptEnable; 633 private IFlagRegisterField txOrderLsbFirst; 634 private IFlagRegisterField rxOrderLsbFirst; 635 private IEnumRegisterField<DeviceMode> mode; 636 637 private IValueRegisterField rxFifoBase; 638 private IValueRegisterField rxFifoLimit; 639 private IValueRegisterField txFifoBase; 640 private IValueRegisterField txFifoLimit; 641 private IValueRegisterField rxFifoWatermarkLevel; 642 private IValueRegisterField txFifoWatermarkLevel; 643 644 private SRAMCircularFifoRange rxFifo; 645 private SRAMCircularFifoRange txFifo; 646 private ArrayMemory underlyingSramMemory; 647 648 private enum DeviceMode 649 { 650 Fw = 0x0, 651 Flash = 0x1, 652 Passthrough = 0x2, 653 } 654 655 public enum Registers 656 { 657 InterruptState = 0x0, 658 InterruptEnable = 0x4, 659 InterruptTest = 0x8, 660 AlertTest = 0xc, 661 Control = 0x10, 662 Configuration = 0x14, 663 FifoLevel = 0x18, 664 AsyncFifoLevel = 0x1c, 665 SPIDevicestatus = 0x20, 666 ReceiverFifoSramPointers = 0x24, 667 TransmitterFifoSramPointers = 0x28, 668 ReceiverFifoSramAddresses = 0x2c, 669 TransmitterFifoSramAddresses = 0x30, 670 InterceptEnable = 0x34, 671 LastReadAddress = 0x38, 672 FlashStatus = 0x3c, 673 JedecCc = 0x40, 674 JedecId = 0x44, 675 ReadThreshold = 0x48, 676 MailboxAddress = 0x4c, 677 UploadStatus = 0x50, 678 UploadStatus2 = 0x54, 679 UploadCmdFifo = 0x58, 680 UploadAddrFifo = 0x5c, 681 CommandFilter = 0x60, 682 AddressSwapMask = 0x80, 683 AddressSwapData = 0x84, 684 PayloadSwapMask = 0x88, 685 PayloadSwapData = 0x8c, 686 CommandInfo = 0x90, 687 CommandInfoEn4b = 0xf0, 688 OpcodeForEX4B = 0xf4, 689 OpcodeforWriteEnable = 0xf8, 690 OpcodeForWriteDisable = 0xfc, 691 TPMCapability = 0x800, 692 TPMConfig = 0x804, 693 TPMStatus = 0x808, 694 TPMAccess0 = 0x80c, 695 TPMAccess1 = 0x810, 696 TPMSts = 0x814, 697 TPMIntfCapability = 0x818, 698 TPMIntCapability = 0x81c, 699 TPMIntVector = 0x820, 700 TPMIntStatus = 0x824, 701 TPMDidVid = 0x828, 702 TPMRid = 0x82c, 703 TPMCommandAndAddressBuffer = 0x830, 704 TPMReadFifo = 0x834, 705 TPMWriteFifo = 0x838, 706 Buffer = 0x1000, 707 } 708 709 private class SRAMCircularFifoRange 710 { SRAMCircularFifoRange(uint baseOffset, uint limit, ArrayMemory underlyingMemory)711 public SRAMCircularFifoRange(uint baseOffset, uint limit, ArrayMemory underlyingMemory) 712 { 713 this.underlyingMemory = underlyingMemory; 714 if(!TryUpdateParameters(baseOffset, limit)) 715 { 716 throw new ArgumentException("SRAMCircularFifo constructor parameters were rejected." + 717 " The range does not fit into the underlying memory or base is bigger than limit"); 718 } 719 } 720 TryUpdateParameters(uint baseOffset, uint limitOffset)721 public bool TryUpdateParameters(uint baseOffset, uint limitOffset) 722 { 723 var baseOffsetInvalid = baseOffset >= (underlyingMemory.Size * 8); 724 var limitOffsetInvalid = limitOffset >= (underlyingMemory.Size * 8); 725 var addressesUnordered = baseOffset > limitOffset; 726 727 if(baseOffsetInvalid || limitOffsetInvalid || addressesUnordered) 728 { 729 return false; 730 } 731 UpdateParameters((ushort)baseOffset, (ushort)limitOffset); 732 return true; 733 } 734 ResetPointers()735 public void ResetPointers() 736 { 737 readPointer = 0; 738 readPhase = false; 739 writePointer = 0; 740 writePhase = false; 741 742 status = FifoStatus.Empty; 743 } 744 TrySetWritePointer(ulong newValue)745 public bool TrySetWritePointer(ulong newValue) 746 { 747 ExtractPhaseAndPointer(newValue, out var phase, out var pointer); 748 if(PointerInDefinedRange(pointer)) 749 { 750 writePointer = checked((ushort)pointer); 751 writePhase = phase; 752 return true; 753 } 754 return false; 755 } 756 WriteByte(byte data)757 public FifoStatus WriteByte(byte data) 758 { 759 underlyingMemory.WriteByte(baseOffset + writePointer, data); 760 761 if(writePointer == limitOffset) 762 { 763 writePointer = baseOffset; 764 writePhase = !writePhase; 765 } 766 else 767 { 768 writePointer++; 769 } 770 UpdateStatus(); 771 return status; 772 } 773 ReadByte(out byte value)774 public FifoStatus ReadByte(out byte value) 775 { 776 value = underlyingMemory.ReadByte(baseOffset + readPointer); 777 readPointer += 1; 778 779 if(readPointer == limitOffset) 780 { 781 readPointer = baseOffset; 782 readPhase = !readPhase; 783 } 784 UpdateStatus(); 785 return status; 786 } 787 TrySetReadPointer(ulong newValue)788 public bool TrySetReadPointer(ulong newValue) 789 { 790 ExtractPhaseAndPointer(newValue, out var phase, out var pointer); 791 if(PointerInDefinedRange(pointer)) 792 { 793 readPointer = checked((ushort)pointer); 794 readPhase = phase; 795 return true; 796 } 797 return false; 798 } 799 800 // As the phase bit is separated from the address, we need to put it back in place 801 public uint ReadPointerWithPhaseBit => readPointer | (uint)((readPhase ? 1 : 0) << 11); 802 public uint WritePointerWithPhaseBit => writePointer | (uint)((writePhase ? 1 : 0) << 11); 803 public bool IsEmpty => (writePointer == readPointer) && (writePhase == readPhase); 804 public bool IsFull => (writePointer == readPointer) && (writePhase != readPhase); 805 public uint Base => baseOffset; 806 public uint Limit => limitOffset; 807 808 public uint CurrentDepth 809 { 810 get 811 { 812 // The depth is guaranteed to be positive as we don't ever read on empty buffer 813 var depth = writePointer - readPointer; 814 var phasesDiffer = writePhase != readPhase; 815 816 if(phasesDiffer) 817 { 818 depth += limitOffset + baseOffset; 819 } 820 return (uint)depth; 821 } 822 } 823 UpdateParameters(ushort baseOffset, ushort limitOffset)824 private void UpdateParameters(ushort baseOffset, ushort limitOffset) 825 { 826 this.baseOffset = baseOffset; 827 this.limitOffset = limitOffset; 828 ResetPointers(); 829 } 830 ExtractPhaseAndPointer(ulong value, out bool phase, out ushort pointer)831 private void ExtractPhaseAndPointer(ulong value, out bool phase, out ushort pointer) 832 { 833 phase = BitHelper.IsBitSet(value, PointerBitsCount + 1); 834 pointer = checked((ushort)(BitHelper.GetValue(value, 0, PointerBitsCount))); 835 } 836 PointerInDefinedRange(uint newValue)837 private bool PointerInDefinedRange(uint newValue) 838 { 839 return (newValue < (limitOffset - baseOffset)); 840 } 841 UpdateStatus()842 private void UpdateStatus() 843 { 844 var phasesDifferent = (readPhase != writePhase); 845 var fifoSize = limitOffset - baseOffset + 1; 846 var addresessDiff = (int)((writePointer - readPointer) + (phasesDifferent ? (fifoSize) : 0)); 847 var lastStatus = status; 848 849 status = FifoStatus.Normal; 850 851 if(addresessDiff == 0) 852 { 853 status = FifoStatus.Empty; 854 } 855 else if(addresessDiff == fifoSize) 856 { 857 status = FifoStatus.Full; 858 } 859 else if(addresessDiff > fifoSize) 860 { 861 status = FifoStatus.Overflow; 862 } 863 else if(addresessDiff < 0) 864 { 865 status = FifoStatus.Underflow; 866 } 867 } 868 869 private ushort baseOffset, limitOffset; 870 private ushort readPointer; 871 private ushort writePointer; 872 873 // This two denotes the state of the buffer pointers. They are flipped on every overflow 874 private bool readPhase; 875 private bool writePhase; 876 private FifoStatus status; 877 878 private readonly ArrayMemory underlyingMemory; 879 880 private const int PointerBitsCount = 11; 881 882 public enum FifoStatus 883 { 884 Empty, 885 Normal, 886 Full, 887 Overflow, 888 Underflow, 889 } 890 } 891 } // End class OpenTitan_SpiDevice 892 } 893