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