1 // 2 // Copyright (c) 2010-2024 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.Peripherals; 12 using Antmicro.Renode.Peripherals.Bus; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Exceptions; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Utilities; 17 using Antmicro.Renode.Utilities.Packets; 18 19 namespace Antmicro.Renode.Peripherals.CRC 20 { 21 public class SAM4S_CRCCU : BasicDoubleWordPeripheral, IKnownSize 22 { SAM4S_CRCCU(IMachine machine)23 public SAM4S_CRCCU(IMachine machine) : base(machine) 24 { 25 IRQ = new GPIO(); 26 DefineRegisters(); 27 } 28 Reset()29 public override void Reset() 30 { 31 base.Reset(); 32 UpdateInterrupts(); 33 } 34 35 public long Size => 0x100; 36 public GPIO IRQ { get; } 37 DefineRegisters()38 private void DefineRegisters() 39 { 40 Registers.DescriptorBase.Define(this) 41 .WithReservedBits(0, 9) 42 .WithValueField(9, 23, 43 out descriptorAddress, 44 name: "DSCR"); // Descriptor Base Address 45 Registers.DMAEnable.Define(this) 46 .WithFlag(0, FieldMode.Write, 47 writeCallback: (_, value) => { if (value) { ComputeCRC(); } }, 48 name: "DMAEN") // DMA Enable bit 49 .WithReservedBits(1, 31); 50 Registers.DMADisable.Define(this) 51 .WithFlag(0, FieldMode.Write, 52 name: "DMADIS") // DMA Disable bit 53 .WithReservedBits(1, 31); 54 Registers.DMAStatus.Define(this) 55 .WithFlag(0, FieldMode.Read, 56 valueProviderCallback: (_) => false, 57 name: "DMASR") // DMA Status bit 58 .WithReservedBits(1, 31); 59 Registers.DMAInterruptEnable.Define(this) 60 .WithFlag(0, FieldMode.Write, 61 writeCallback: (_, value) => { if (value) { this.interruptEnableDMA = true; } }, 62 name: "DMAIER") // DMA Interrupt Enable bit 63 .WithReservedBits(1, 31); 64 Registers.DMAInterruptDisable.Define(this) 65 .WithFlag(0, FieldMode.Write, 66 writeCallback: (_, value) => { if (value) { this.interruptEnableDMA = false; } }, 67 name: "DMAIDR") // DMA Interrupt Disable bit 68 .WithReservedBits(1, 31); 69 Registers.DMAInterruptMask.Define(this) 70 .WithFlag(0, FieldMode.Write, 71 writeCallback: (_, value) => { this.interruptMaskDMA = value; }, 72 name: "DMAIMR") // DMA Interrupt Mask bit 73 .WithReservedBits(1, 31); 74 Registers.DMAInterruptStatus.Define(this) 75 .WithFlag(0, FieldMode.Read, 76 valueProviderCallback: _ => { var ret = transferDone; transferDone = false; return ret; }, 77 name: "DMAISR") // DMA Interrupt Status bit. This flag is reset after read. 78 .WithReservedBits(1, 31); 79 Registers.Control.Define(this) 80 .WithFlag(0, FieldMode.Read | FieldMode.WriteOneToClear, 81 valueProviderCallback: _ => false, 82 name: "RESET") // CRC Computation Reset 83 .WithReservedBits(1, 31) 84 .WithWriteCallback((_, __) => { crcConfigDirty = true; }); 85 Registers.Mode.Define(this) 86 .WithFlag(0, 87 valueProviderCallback: _ => this.globalEnable, 88 writeCallback: (_, value) => { this.globalEnable = value; }, 89 name: "ENABLE") // CRC Enable 90 .WithFlag(1, 91 valueProviderCallback: _ => this.compareMode, 92 writeCallback: (_, value) => { this.compareMode = value; }, 93 name: "COMPARE") // CRC Compare 94 .WithEnumField(2, 2, 95 out poly, 96 name: "PTYPE") // Primitive Polynomial 0 - CCITT8023, 1 - CASTAGNOLI, 2 - CCITT16 97 .WithTag("DIVIDER", 4, 4) // Request Divider 98 .WithReservedBits(8, 24) 99 .WithWriteCallback((_, __) => { crcConfigDirty = true; }); 100 Registers.Status.Define(this) 101 .WithValueField(0, 32, FieldMode.Read, 102 valueProviderCallback: _ => CRC.Value, 103 name: "CRC"); // Cyclic Redundancy Check Value 104 Registers.InterruptEnable.Define(this) 105 .WithFlag(0, FieldMode.Write, 106 writeCallback: (_, value) => { if (value) { this.interruptEnableError = true; } }, 107 name: "ERRIER") // Error Interrupt Enable bit 108 .WithReservedBits(1, 31); 109 Registers.InterruptDisable.Define(this) 110 .WithFlag(0, FieldMode.Write, 111 writeCallback: (_, value) => { if (value) { this.interruptEnableError = false; } }, 112 name: "ERRIDR") // Error Interrupt Disable bit 113 .WithReservedBits(1, 31); 114 Registers.InterruptMask.Define(this) 115 .WithFlag(0, FieldMode.Write, 116 writeCallback: (_, value) => { this.interruptMaskError = value; }, 117 name: "ERRIMR") // Error Interrupt Mask bit 118 .WithReservedBits(1, 31); 119 Registers.InterruptStatus.Define(this) 120 .WithFlag(0, FieldMode.Read, 121 valueProviderCallback: _ => this.InterruptStatusError, 122 name: "ERRISR") // Error Interrupt Status bit 123 .WithReservedBits(1, 31); 124 } 125 UpdateInterrupts()126 private void UpdateInterrupts() 127 { 128 var state = MaskedErrorInterruptStatus || MaskedDMAInterruptStatus; 129 this.DebugLog("Setting IRQ to {0}", state ? "set" : "unset"); 130 IRQ.Set(state); 131 } 132 ReloadCRCConfig()133 private void ReloadCRCConfig() 134 { 135 var config = new CRCConfig( 136 polyMap[poly.Value], 137 reflectInput: false, 138 reflectOutput: false, 139 init: 0xFFFFFFFF, 140 xorOutput: 0x0 141 ); 142 if(crc == null || !config.Equals(crc.Config)) 143 { 144 crc = new CRCEngine(config); 145 } 146 else 147 { 148 crc.Reset(); 149 } 150 crcConfigDirty = false; 151 } 152 ComputeCRC()153 private void ComputeCRC() 154 { 155 if(globalEnable) 156 { 157 tcRegisters = TransferControlPacket.ReadFrom(this.descriptorAddress.Value << 9, this.sysbus); 158 var data = this.sysbus.ReadBytes(tcRegisters.transferAddress, (int)tcRegisters.transferSize * tcRegisters.readByteMultiplier); 159 CRC.Calculate(data); 160 transferDone = true; 161 UpdateInterrupts(); 162 } 163 else 164 { 165 this.Log(LogLevel.Warning, "Trying to compute CRC without setting the ENABLE bit in CRCCU_MR"); 166 } 167 } 168 169 private CRCEngine CRC 170 { 171 get 172 { 173 if(crc == null || crcConfigDirty) 174 { 175 ReloadCRCConfig(); 176 } 177 return crc; 178 } 179 } 180 181 private bool MaskedDMAInterruptStatus => transferDone && interruptEnableDMA && interruptMaskDMA && tcRegisters.contextDoneInterruptEnable; 182 183 private bool InterruptStatusError => (CRC.Value != tcRegisters.referenceCRC) && compareMode; 184 185 private bool MaskedErrorInterruptStatus => InterruptStatusError && interruptEnableError && interruptMaskError; 186 187 private bool crcConfigDirty; 188 private bool compareMode; 189 private bool globalEnable; 190 private bool interruptEnableDMA; 191 private bool interruptEnableError; 192 private bool interruptMaskDMA; 193 private bool interruptMaskError; 194 private bool transferDone; 195 private CRCEngine crc; 196 private IValueRegisterField descriptorAddress; 197 private IEnumRegisterField<CRCPolyType> poly; 198 private TransferControlPacket tcRegisters; 199 private static readonly Dictionary<CRCPolyType, CRCPolynomial> polyMap = new Dictionary<CRCPolyType, CRCPolynomial> () 200 { 201 { 202 CRCPolyType.CRC32, 203 CRCPolynomial.CRC32 204 }, 205 { 206 CRCPolyType.CRC32C, 207 CRCPolynomial.CRC32C 208 }, 209 { 210 CRCPolyType.CRC16_CCITT, 211 CRCPolynomial.CRC16_CCITT 212 }, 213 }; 214 215 private enum CRCPolyType : byte 216 { 217 CRC32 = 0x0, 218 CRC32C = 0x1, 219 CRC16_CCITT = 0x2 220 } 221 222 private enum Registers : long 223 { 224 DescriptorBase = 0x0, 225 DMAEnable = 0x8, 226 DMADisable = 0xC, 227 DMAStatus = 0x10, 228 DMAInterruptEnable = 0x14, 229 DMAInterruptDisable = 0x18, 230 DMAInterruptMask = 0x1C, 231 DMAInterruptStatus = 0x20, 232 Control = 0x34, 233 Mode = 0x38, 234 Status = 0x3C, 235 InterruptEnable = 0x40, 236 InterruptDisable = 0x44, 237 InterruptMask = 0x48, 238 InterruptStatus = 0x4C 239 } 240 241 [LeastSignificantByteFirst] 242 private struct TransferControlPacket 243 { 244 #pragma warning disable 649 245 [PacketField, Offset(doubleWords: 0, bits: 0), Width(32)] 246 public uint transferAddress; 247 [PacketField, Offset(doubleWords: 1, bits: 0), Width(16)] 248 public uint transferSize; 249 [PacketField, Offset(doubleWords: 1, bits: 24), Width(2)] 250 public uint transferWidth; 251 [PacketField, Offset(doubleWords: 1, bits: 27), Width(1)] 252 public bool contextDoneInterruptEnable; 253 [PacketField, Offset(doubleWords: 4, bits: 0), Width(32)] 254 public uint referenceCRC; 255 #pragma warning restore 649 256 257 public int readByteMultiplier; 258 ReadFromAntmicro.Renode.Peripherals.CRC.SAM4S_CRCCU.TransferControlPacket259 public static TransferControlPacket ReadFrom(ulong address, IBusController sysbus) 260 { 261 var tcBuffer = sysbus.ReadBytes(address, Packet.CalculateLength<TransferControlPacket>()); 262 var tcRegisters = Packet.Decode<TransferControlPacket>(tcBuffer); 263 switch(tcRegisters.transferWidth) 264 { 265 case 1: 266 // HALFWORD 267 tcRegisters.readByteMultiplier = 2; 268 break; 269 case 2: 270 // WORD 271 tcRegisters.readByteMultiplier = 4; 272 break; 273 default: 274 // BYTE 275 tcRegisters.readByteMultiplier = 1; 276 break; 277 } 278 return tcRegisters; 279 } 280 } 281 } 282 } 283