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