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;
8 using System.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.Bus;
14 
15 namespace Antmicro.Renode.Peripherals.SPI
16 {
17     [AllowedTranslations(AllowedTranslation.ByteToWord | AllowedTranslation.WordToByte)]
18     public class NPCX_SPIP : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IWordPeripheral, IKnownSize
19     {
NPCX_SPIP(IMachine machine)20         public NPCX_SPIP(IMachine machine) : base(machine)
21         {
22             DefineRegisters();
23             IRQ = new GPIO();
24         }
25 
Reset()26         public override void Reset()
27         {
28             registerCollection.Reset();
29             data = 0;
30         }
31 
ReadWord(long offset)32         public ushort ReadWord(long offset)
33         {
34             return registerCollection.Read(offset);
35         }
36 
WriteWord(long offset, ushort value)37         public void WriteWord(long offset, ushort value)
38         {
39             registerCollection.Write(offset, value);
40         }
41 
42         public long Size => 0x1000;
43         public GPIO IRQ { get; }
44 
DefineRegisters()45         private void DefineRegisters()
46         {
47             var registersMap = new Dictionary <long, WordRegister>();
48 
49             registersMap[(long)Registers.DataInOut] = new WordRegister(this)
50                 .WithValueField(0, 16,
51                     writeCallback: (_, val) => WriteData(val),
52                     valueProviderCallback: _ => ReadData(),
53                     name: "DATA (SPIP Read/Write Data)")
54                 .WithChangeCallback((_,__) => UpdateInterrupts());
55 
56             registersMap[(long)Registers.Control1] = new WordRegister(this)
57                 .WithFlag(0, out isEnabled, name: "SPIEN (SPI Enable)")
58                 .WithReservedBits(1, 1)
59                 .WithFlag(2, out is16BitMode, name: "MOD (Data Interface Mode)")
60                 .WithReservedBits(3, 2)
61                 .WithFlag(5, out enableIrqRead, name: "EIR (Enable Interrupt for Read)")
62                 .WithFlag(6, out enableIrqWrite, name: "EIW (Enable Interrupt for Write)")
63                 .WithTag("SCM (Clocking Mode)", 7, 1)
64                 .WithTag("SCIDL (Value of SPI_SCLK when Bus is Idle)", 8, 1)
65                 .WithTag("SCDV6-0 (Shift Clock Divider Value)", 9, 7)
66                 .WithWriteCallback((_, __) => UpdateInterrupts());
67 
68             registersMap[(long)Registers.Status] = new WordRegister(this)
69                 .WithTag("BSY (Shift Register Busy)", 0, 1)
70                 .WithFlag(1, out readBufferFull, name: "RBF (Read Buffer Full)")
71                 .WithReservedBits(2, 14);
72 
73             registerCollection = new WordRegisterCollection(this, registersMap);
74         }
75 
WriteData(ulong val)76         private void WriteData(ulong val)
77         {
78             if(!isEnabled.Value)
79             {
80                 this.Log(LogLevel.Warning, "Tried to write data while peripheral is not enabled: 0x{0:X} Aborting!", val);
81                 return;
82             }
83             data = RegisteredPeripheral.Transmit((byte)val);
84             if(is16BitMode.Value)
85             {
86                 data |= (ushort)((ushort)RegisteredPeripheral.Transmit((byte)(val >> 8)) << 8);
87             }
88             readBufferFull.Value = true;
89         }
90 
ReadData()91         private ulong ReadData()
92         {
93             if(!isEnabled.Value)
94             {
95                 this.Log(LogLevel.Warning, "Tried to read data while peripheral is not enabled. Returning 0!");
96                 return 0;
97             }
98             readBufferFull.Value = false;
99 
100             var result = (is16BitMode.Value ? data : (byte)data);
101             data = 0;
102             return result;
103         }
104 
UpdateInterrupts()105         private void UpdateInterrupts()
106         {
107             var state = enableIrqRead.Value && readBufferFull.Value;
108             this.DebugLog("IRQ {0}.", state ? "set" : "unset");
109             IRQ.Set(state);
110         }
111 
112         private WordRegisterCollection registerCollection;
113 
114         private ushort data;
115         private IFlagRegisterField isEnabled;
116         private IFlagRegisterField is16BitMode;
117         private IFlagRegisterField enableIrqRead;
118         private IFlagRegisterField enableIrqWrite;
119         private IFlagRegisterField readBufferFull;
120 
121         private enum Registers
122         {
123             DataInOut = 0x0,
124             Control1 = 0x2,
125             Status = 0x4
126         }
127     }
128 }
129