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.Peripherals.Bus; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.SPI 17 { 18 [AllowedTranslations(AllowedTranslation.DoubleWordToByte)] 19 public class NPCX_FIU : NullRegistrationPointPeripheralContainer<ISPIPeripheral>, IBytePeripheral, IProvidesRegisterCollection<ByteRegisterCollection>, IKnownSize 20 { NPCX_FIU(IMachine machine)21 public NPCX_FIU(IMachine machine) : base(machine) 22 { 23 RegistersCollection = new ByteRegisterCollection(this); 24 DefineRegisters(); 25 Reset(); 26 } 27 Reset()28 public override void Reset() 29 { 30 userModeAccessLocked = false; 31 userModeAccessAddress = 0x0; 32 userModeAccessData = 0x0; 33 use4ByteAddress = false; 34 } 35 ReadByte(long offset)36 public byte ReadByte(long offset) 37 { 38 return RegistersCollection.Read(offset); 39 } 40 WriteByte(long offset, byte value)41 public void WriteByte(long offset, byte value) 42 { 43 RegistersCollection.Write(offset, value); 44 } 45 46 public long Size => 0x1000; 47 public ByteRegisterCollection RegistersCollection { get; } 48 DefineRegisters()49 private void DefineRegisters() 50 { 51 Registers.UMACodeByte.Define(this) 52 .WithValueField(0, 8, out userModeAccessCode, name: "TR_CODE (Transaction Code)"); 53 54 Registers.UMAAddressByte0_0.DefineMany(this, 3, (register, i) => 55 { 56 register 57 .WithValueField(0, 8, name: $"ADDR_B{i} (Address Byte {i})", 58 valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessAddress, i * 8, 8), 59 writeCallback: (_, value) => BitHelper.SetMaskedValue(ref userModeAccessAddress, (byte)value, i * 8, 8)); 60 }); 61 62 Registers.UMADataByte0_0.DefineMany(this, 4, (register, i) => 63 { 64 register 65 .WithValueField(0, 8, name: $"DAT_B{i} (Data Byte {i})", 66 valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessData, i * 8, 8), 67 writeCallback: (_, value) => BitHelper.SetMaskedValue(ref userModeAccessData, (byte)value, i * 8, 8)); 68 }); 69 70 Registers.UMAControlAndStatus.Define(this, 0x40) 71 .WithValueField(0, 3, out var dataWidth, name: "D_SIZE (Data Field Size Select)") 72 .WithFlag(3, out var addressWidthSelect, name: "A_SIZE (Address Field Size Select)") 73 .WithFlag(4, out var skipCodeField, name: "C_SIZE (Code Field Size Select)") 74 .WithFlag(5, out var isWrite, name: "RD_WR (Read/Write Select)") 75 .WithReservedBits(6, 1, allowedValue: 0x1) 76 .WithFlag(7, out var umaTransactionStart, name: "EXEC_DONE (Operation Execute/Done)") 77 .WithWriteCallback((_, __) => 78 { 79 if(!umaTransactionStart.Value) 80 { 81 return; 82 } 83 umaTransactionStart.Value = false; 84 85 if(userModeAccessLocked) 86 { 87 this.ErrorLog("Attempted to start a UMA transaction while UMA_LOCK is active"); 88 return; 89 } 90 91 var addressWidth = (int)userModeAccessAddressSize.Value; 92 if(addressWidthSelect.Value) 93 { 94 addressWidth = use4ByteAddress ? 4 : 3; 95 } 96 97 var skipCode = skipCodeField.Value; 98 if(isWrite.Value) 99 { 100 skipCode = false; 101 } 102 103 PerformUserModeAccessTransaction(addressWidth, (int)dataWidth.Value, isWrite.Value, skipCode); 104 }); 105 106 Registers.UMAExtendedControlAndStatus.Define(this, 0x3) 107 .WithReservedBits(0, 1, allowedValue: 0x1) 108 .WithFlag(1, out softwareChipSelect, name: "SW_CS1 (Software Controlled Chip-Select 1n)", 109 changeCallback: (_, value) => 110 { 111 if(!value) 112 { 113 return; 114 } 115 116 RegisteredPeripheral?.FinishTransmission(); 117 }) 118 .WithTaggedFlag("SEC_CS (Secondary Chip-Select)", 2) 119 .WithFlag(3, name: "UMA_LOCK (UMA Operation Lock)", 120 valueProviderCallback: _ => userModeAccessLocked, 121 writeCallback: (_, value) => 122 { 123 if(userModeAccessLocked) 124 { 125 return; 126 } 127 128 userModeAccessLocked = value; 129 }) 130 .WithValueField(4, 3, out userModeAccessAddressSize, name: "UMA_ADDR_SIZE (Address Field Size Select)") 131 .WithReservedBits(7, 1); 132 133 Registers.UMADataByte1_0.DefineMany(this, 4, (register, i) => 134 { 135 register 136 .WithValueField(0, 8, FieldMode.Read, name: $"DAT_B{i} (Data Byte {i})", 137 valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessData, i * 8, 8)); 138 }); 139 140 Registers.UMAAddressByte1_0.DefineMany(this, 4, (register, i) => 141 { 142 register 143 .WithValueField(0, 8, name: $"ADDR_B{i} (Address Byte {i})", 144 valueProviderCallback: _ => (byte)BitHelper.GetValue(userModeAccessAddress, i * 8, 8), 145 writeCallback: (_, value) => BitHelper.SetMaskedValue(ref userModeAccessAddress, (byte)value, i * 8, 8)); 146 }); 147 148 Registers.SPI1Device.Define(this) 149 .WithTag("SPI1_LO_DEV_SIZE (SPI0 Low Device size)", 0, 4) 150 .WithReservedBits(4, 2) 151 .WithFlag(6, out var use4ByteCS10, name: "FOUR_BADDR_CS10 (Four Bytes Address for Chip-Select 10)") 152 .WithFlag(7, out var use4ByteCS11, name: "FOUR_BADDR_CS11 (Four Bytes Address for Chip-Select 11)") 153 .WithWriteCallback((_, __) => 154 { 155 use4ByteAddress = use4ByteCS10.Value || use4ByteCS11.Value; 156 }); 157 } 158 PerformUserModeAccessTransaction(int addressWidth, int dataWidth, bool isWrite, bool skipCode)159 private void PerformUserModeAccessTransaction(int addressWidth, int dataWidth, bool isWrite, bool skipCode) 160 { 161 if(RegisteredPeripheral == null) 162 { 163 this.ErrorLog("Attempted to perform a UMA transaction with no peripheral attached"); 164 return; 165 } 166 167 if(!skipCode) 168 { 169 RegisteredPeripheral.Transmit((byte)userModeAccessCode.Value); 170 } 171 172 for(var i = 0; i < addressWidth; i++) 173 { 174 RegisteredPeripheral.Transmit((byte)BitHelper.GetValue(userModeAccessAddress, i * 8, 8)); 175 } 176 177 for(var i = 0; i < dataWidth; i++) 178 { 179 var value = RegisteredPeripheral.Transmit((byte)BitHelper.GetValue(userModeAccessData, i * 8, 8)); 180 if(!isWrite) 181 { 182 BitHelper.SetMaskedValue(ref userModeAccessData, value, i * 8, 8); 183 } 184 } 185 186 if(softwareChipSelect.Value) 187 { 188 RegisteredPeripheral.FinishTransmission(); 189 } 190 } 191 192 private IValueRegisterField userModeAccessCode; 193 private IValueRegisterField userModeAccessAddressSize; 194 private IFlagRegisterField softwareChipSelect; 195 196 private uint userModeAccessAddress; 197 private uint userModeAccessData; 198 private bool userModeAccessLocked; 199 private bool use4ByteAddress; 200 201 private enum Registers 202 { 203 BurstConfiguration = 0x01, // BURST_CFG 204 ResponseConfiguration = 0x02, // RESP_CFG 205 SPIFlashConfiguration = 0x14, // SPI_FL_CFG 206 UMACodeByte = 0x16, // UMA_CODE 207 UMAAddressByte0_0 = 0x17, // UMA_AB0 208 UMAAddressByte0_1 = 0x18, // UMA_AB1 209 UMAAddressByte0_2 = 0x19, // UMA_AB2 210 UMADataByte0_0 = 0x1A, // UMA_DB0 211 UMADataByte0_1 = 0x1B, // UMA_DB1 212 UMADataByte0_2 = 0x1C, // UMA_DB2 213 UMADataByte0_3 = 0x1D, // UMA_DB3 214 UMAControlAndStatus = 0x1E, // UMA_CTS 215 UMAExtendedControlAndStatus = 0x1F, // UMA_ECTS 216 UMADataByte1_0 = 0x20, // UMA_DB0 NOTE: This is a read-only mirror of the UMA_DB0-3 217 UMADataByte1_1 = 0x21, // UMA_DB1 218 UMADataByte1_2 = 0x22, // UMA_DB2 219 UMADataByte1_3 = 0x23, // UMA_DB3 220 CRCControl = 0x26, // CRCCON 221 CRCResult = 0x27, // CRCRSLT 222 FIUReadCommand = 0x30, // FIU_RD_CMD 223 FIUDummyCycle = 0x32, // FIU_DMM_CYC 224 FIUExtendedConfiguration = 0x33, // FIU_EXT_CFG 225 UMAAddressByte1_0 = 0x34, // UMA_AB0 NOTE: Only to be used with external flash 226 UMAAddressByte1_1 = 0x35, // UMA_AB1 and when UMA_ADDR_SIZE is 4 227 UMAAddressByte1_2 = 0x36, // UMA_AB2 228 UMAAddressByte1_3 = 0x37, // UMA_AB3 229 SPI1Device = 0x3D, // SPI1_DEV 230 } 231 } 232 } 233 234