1 // 2 // Copyright (c) 2010-2019 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 Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Peripherals.Bus; 15 using Antmicro.Renode.Utilities; 16 17 namespace Antmicro.Renode.Peripherals.SPI 18 { 19 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)] 20 public class LiteX_SPI_Flash : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IDoubleWordPeripheral, IKnownSize 21 { LiteX_SPI_Flash(IMachine machine)22 public LiteX_SPI_Flash(IMachine machine) : base(machine) 23 { 24 bbHelper = new BitBangHelper(8, loggingParent: this, outputMsbFirst: true); 25 26 var registers = new Dictionary<long, DoubleWordRegister> 27 { 28 {(long)Registers.BitBang, new DoubleWordRegister(this) 29 .WithFlag(0, out var valueSignal, FieldMode.Write, name: "value") 30 .WithFlag(1, out var clockSignal, FieldMode.Write, name: "clk") 31 .WithFlag(2, out var chipSelectNegatedSignal, FieldMode.Write, name: "cs_n") 32 .WithFlag(3, out var dqInputSignal, FieldMode.Write, name: "dq_input") 33 .WithWriteCallback((_, val) => 34 { 35 if(!bitBangEnabled.Value) 36 { 37 this.Log(LogLevel.Warning, "Write to not-enabled BitBang register ignored"); 38 return; 39 } 40 41 if(RegisteredPeripheral == null) 42 { 43 this.Log(LogLevel.Warning, "Trying to send bytes over SPI, but there is no device attached"); 44 return; 45 } 46 47 if(chipSelectNegatedSignal.Value && !previousChipSelectNegatedSignal) 48 { 49 this.Log(LogLevel.Noisy, "ChipSelect signal down - finishing the transmission"); 50 RegisteredPeripheral.FinishTransmission(); 51 } 52 previousChipSelectNegatedSignal = chipSelectNegatedSignal.Value; 53 54 // do not latch bits when dqInputSignal is set or chipSelect is not set 55 if(bbHelper.Update(clockSignal.Value, valueSignal.Value, !dqInputSignal.Value && !chipSelectNegatedSignal.Value)) 56 { 57 this.Log(LogLevel.Noisy, "Sending byte 0x{0:X}", bbHelper.DecodedOutput); 58 var input = RegisteredPeripheral.Transmit((byte)bbHelper.DecodedOutput); 59 this.Log(LogLevel.Noisy, "Received byte 0x{0:X}", input); 60 61 bbHelper.SetInputBuffer(input); 62 } 63 }) 64 }, 65 66 {(long)Registers.Miso, new DoubleWordRegister(this) 67 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => bbHelper.EncodedInput) 68 }, 69 70 {(long)Registers.BitBangEnable, new DoubleWordRegister(this) 71 .WithFlag(0, out bitBangEnabled) 72 } 73 }; 74 75 registersCollection = new DoubleWordRegisterCollection(this, registers); 76 Reset(); 77 } 78 Reset()79 public override void Reset() 80 { 81 bbHelper.Reset(); 82 registersCollection.Reset(); 83 previousChipSelectNegatedSignal = true; 84 } 85 ReadDoubleWord(long offset)86 public uint ReadDoubleWord(long offset) 87 { 88 return registersCollection.Read(offset); 89 } 90 91 [ConnectionRegionAttribute("xip")] XipReadDoubleWord(long offset)92 public uint XipReadDoubleWord(long offset) 93 { 94 return (RegisteredPeripheral as IDoubleWordPeripheral)?.ReadDoubleWord(offset) ?? 0; 95 } 96 WriteDoubleWord(long offset, uint value)97 public void WriteDoubleWord(long offset, uint value) 98 { 99 registersCollection.Write(offset, value); 100 } 101 102 [ConnectionRegionAttribute("xip")] XipWriteDoubleWord(long offset, uint value)103 public void XipWriteDoubleWord(long offset, uint value) 104 { 105 (RegisteredPeripheral as IDoubleWordPeripheral)?.WriteDoubleWord(offset, value); 106 } 107 108 public long Size => 0x10; 109 110 private bool previousChipSelectNegatedSignal; 111 112 private readonly DoubleWordRegisterCollection registersCollection; 113 private readonly IFlagRegisterField bitBangEnabled; 114 private readonly BitBangHelper bbHelper; 115 116 private enum Registers 117 { 118 BitBang = 0x0, 119 Miso = 0x4, 120 BitBangEnable = 0x8 121 } 122 } 123 } 124