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 System.Linq;
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 using Range = Antmicro.Renode.Core.Range;
18 
19 namespace Antmicro.Renode.Peripherals.PCI
20 {
21     [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)]
22     public class PCIHost_Bridge : SimpleContainer<IPCIePeripheral>, IPCIeRouter, IDoubleWordPeripheral, IAbsoluteAddressAware, IKnownSize
23     {
PCIHost_Bridge(IMachine machine)24         public PCIHost_Bridge(IMachine machine) : base(machine)
25         {
26             registers = CreateRegisters();
27         }
28 
ReadDoubleWord(long offset)29         public uint ReadDoubleWord(long offset)
30         {
31             var value = registers.Read(offset);
32             return value;
33         }
34 
WriteDoubleWord(long offset, uint value)35         public void WriteDoubleWord(long offset, uint value)
36         {
37             registers.Write(offset, value);
38         }
39 
SetAbsoluteAddress(ulong address)40         public void SetAbsoluteAddress(ulong address)
41         {
42             // Youngest bit denotes IO/Memory type, second one is reserved
43             currentAccessAbsoluteAddress = address & ~3ul;
44         }
45 
Reset()46         public override void Reset()
47         {
48             registers.Reset();
49 
50             address = 0;
51         }
52 
RegisterBar(Range range, IPCIePeripheral peripheral, uint bar)53         public void RegisterBar(Range range, IPCIePeripheral peripheral, uint bar)
54         {
55             /* Unimplemented, dummy required by IPCIePeripheral interface */
56             return;
57         }
58 
59         public long Size => 0x10;
60 
61         protected struct TargetBar
62         {
63             public IPCIePeripheral TargetPeripheral;
64             public uint BarNumber;
65         }
66 
CreateRegisters()67         private DoubleWordRegisterCollection CreateRegisters()
68         {
69             var registersDictionary = new Dictionary<long, DoubleWordRegister>
70             {
71                 {(long)Registers.ConfigAddress, new DoubleWordRegister(this)
72                     .WithReservedBits(0, 2)
73                     .WithValueField(2, 6, out registerNumber, name: "Register Number")
74                     .WithValueField(8, 3, out functionNumber, name: "Function Number")
75                     .WithValueField(11, 5, out deviceNumber, name: "Device Number")
76                     .WithValueField(16, 8, out busNumber, name: "Bus Number")
77                     .WithReservedBits(24, 7)
78                     .WithFlag(31, out configEnabled, name: "Enable")
79                     .WithWriteCallback((_, value) => { address = value; })
80                 },
81                 {(long)Registers.ConfigData, new DoubleWordRegister(this)
82                     .WithValueField(0, 32, writeCallback: (_, value) => WriteData((uint)value),
83                         valueProviderCallback: _ => ReadData(), name: "CONFIG_DATA")
84                 },
85             };
86             return new DoubleWordRegisterCollection(this, registersDictionary);
87         }
88 
WriteData(uint data)89         private void WriteData(uint data)
90         {
91             if(!configEnabled.Value)
92             {
93                 this.Log(LogLevel.Warning, "Writing data to device in unhandled state, value : {0:X}", data);
94                 return;
95             }
96 
97             if(selectedDevice != null)
98             {
99                 selectedDevice.ConfigurationWriteDoubleWord((long)registerNumber.Value*4, data);
100             }
101             else
102             {
103                 this.Log(LogLevel.Warning, "Trying to write to unexsiting device. Value: {0:X}", data);
104             }
105         }
106 
ReadData()107         private uint ReadData()
108         {
109             if(configEnabled.Value)
110             {
111                 if(!ChildCollection.TryGetValue((int)deviceNumber.Value, out selectedDevice))
112                 {
113                     this.Log(LogLevel.Warning, "Selected unregistered device number : {0}", deviceNumber.Value);
114                     selectedDevice = null;
115                     return 0;
116                 }
117                 //Address is multiplied by 4 cause Read function take offset as argument
118                 return selectedDevice.ConfigurationReadDoubleWord((long)registerNumber.Value * 4);
119             }
120             else
121             {
122                 this.Log(LogLevel.Warning, "Reading data from device in unhandled state");
123             }
124             return 0;
125         }
126 
127         private readonly DoubleWordRegisterCollection registers;
128         private IFlagRegisterField configEnabled;
129         private IValueRegisterField registerNumber;
130         private IValueRegisterField functionNumber;
131         private IValueRegisterField deviceNumber;
132         private IValueRegisterField busNumber;
133         private IPCIePeripheral selectedDevice;
134 
135         private ulong currentAccessAbsoluteAddress;
136         private uint address;
137 
138         private enum Registers
139         {
140             ConfigAddress = 0x0,
141             ConfigData = 0x4,
142         }
143     }
144 }
145