1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using Antmicro.Renode.Core;
9 using Antmicro.Renode.Core.Structure;
10 using Antmicro.Renode.Logging;
11 using Antmicro.Renode.Peripherals.Bus;
12 
13 namespace Antmicro.Renode.Peripherals.PCI
14 {
15     public class VersatilePCI : SimpleContainer<IPCIPeripheral>, IDoubleWordPeripheral
16     {
VersatilePCI(IMachine machine)17         public VersatilePCI(IMachine machine) : base(machine)
18         {
19             info = new PCIInfo[4];
20             _info = new bool[4];
21             int i;
22             for(i = 0; i < 4; i++)
23             {
24                 _info[i] = false;
25             }
26         }
27 
Register(IPCIPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)28         public override void Register(IPCIPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)
29         {
30             base.Register(peripheral, registrationPoint);
31             info[registrationPoint.Address] = peripheral.GetPCIInfo();
32             _info[registrationPoint.Address] = true;
33         }
34 
35         [ConnectionRegion("config")]
ReadDoubleWordConfig(long offset)36         public uint ReadDoubleWordConfig(long offset)
37         {
38             switch(offset)
39             {
40             case 0x0:
41                 return 0x030010ee;  // DEVICE_ID
42             case 0x8:
43                 return 0x0b400000; // CLASS_ID
44             }
45             return 0;
46         }
47 
48         [ConnectionRegion("config")]
WriteDoubleWordConfig(long offset, uint value)49         public void WriteDoubleWordConfig(long offset, uint value)
50         {
51         }
52 
ReadDoubleWord(long offset)53         public virtual uint ReadDoubleWord(long offset)
54         {
55             //if (offset < 0x800) return 0;
56             //offset -= 0x800;
57             int pci_num = (int)(offset / 0x800);
58             if(pci_num > 3)
59                 return 0;
60             if(!_info[pci_num])
61                 return 0;
62             PCIInfo linfo = info[pci_num];
63             offset -= pci_num * 0x800;
64             if(offset == 0x00)
65                 return  (uint)linfo.vendor_id + (uint)(linfo.device_id << 16);
66             if(offset == 0x04)
67                 return (1 << 25) | (1 << 1) | (1 << 0); // cmd ?
68             if(offset == 0x08)
69                 return (uint)(linfo.device_class << 16); // class
70             if(offset == 0x0c)
71                 return 0x8; // ?
72             if((offset >= 0x10) && (offset < 0x2c))
73             {
74                 uint bar_id = (uint)((offset - 0x10) / 4);
75                 return linfo.BAR[bar_id];
76             }
77             if(offset == 0x2c)
78                 return  (uint)linfo.sub_vendor_id + (uint)(linfo.sub_device_id << 16);
79             if(offset == 0x30)
80                 return 0x1; // rom ?
81             if(offset == 0x3c)
82                 return (uint)((0x1 << 8) | (24 + pci_num)); // slot 24 pin 1 (pci0), slot 25 pin 1 (pci1) ...
83             if(offset == 0x34)
84                 return 0x1; // ?
85             return 0;
86         }
87 
WriteDoubleWord(long offset, uint value)88         public virtual void WriteDoubleWord(long offset, uint value)
89         {
90             //if (offset < 0x800) return;
91             //offset -= 0x800;
92             int pci_num = (int)(offset / 0x800);
93             if(pci_num > 3)
94                 return;
95             if(!_info[pci_num])
96                 return;
97             PCIInfo linfo = info[pci_num];
98             offset -= pci_num * 0x800;
99             if((offset >= 0x10) && (offset < 0x2c))
100             {
101                 uint bar_id = (uint)((offset - 0x10) / 4);
102                 if(value == 0xFFFFFFFF)
103                 {
104                     linfo.BAR[bar_id] = linfo.BAR_len[bar_id];
105                 }
106                 else
107                 {
108                     linfo.BAR[bar_id] = value;
109                 }
110             }
111         }
112 
113         [ConnectionRegion("io")]
WriteDoubleWordIO(long offset, uint value)114         public void WriteDoubleWordIO(long offset, uint value)
115         {
116             this.Log(LogLevel.Noisy, "writeIO {0:X}, value 0x{1:X}", offset, value);
117 
118             int found = -1;
119             int bar_no = -1;
120             for(int c = 0; c < 3; c++)
121             {
122                 if(!_info[c])
123                     continue;
124                 for(int i = 0; i < 8; i++)
125                 {
126                     if(info[c].BAR_len[i] == 0)
127                         continue;
128                     if((offset >= (info[c].BAR[i] & 0x0FFFFFFF)) && (offset < ((info[c].BAR[i] & 0xFFFFFFF) + info[c].BAR_len[i])))
129                     {
130                         found = c;
131                         bar_no = i;
132                         break;
133                     }
134                 }
135             }
136             if(found == -1)
137                 return;
138 
139             PCIInfo linfo = info[found];
140             offset -= (linfo.BAR[bar_no] & 0xFFFFFFF);
141             IPCIPeripheral pci_device = GetByAddress(found);
142             pci_device.WriteDoubleWordPCI((uint)bar_no, offset, value);
143         }
144 
145         [ConnectionRegion("io")]
ReadDoubleWordIO(long offset)146         public uint ReadDoubleWordIO(long offset)
147         {
148             this.Log(LogLevel.Noisy, "readIO {0:X}", offset);
149 
150             // (1) search for pci slot and bar no
151             int found = -1;
152             int bar_no = -1;
153             for(int c = 0; c < 3; c++)
154             {
155                 if(!_info[c])
156                     continue;
157                 for(int i = 0; i < 8; i++)
158                 {
159                     if(info[c].BAR_len[i] == 0)
160                         continue;
161                     if((offset >= (info[c].BAR[i] & 0x0FFFFFFF)) && (offset < ((info[c].BAR[i] & 0xFFFFFFF) + info[c].BAR_len[i])))
162                     {
163                         found = c;
164                         bar_no = i;
165                         break;
166                     }
167                 }
168             }
169             if(found == -1)
170                 return 0;
171 
172             // (2) forward read
173             PCIInfo linfo = info[found];
174             offset -= (linfo.BAR[bar_no] & 0xFFFFFFF);
175             IPCIPeripheral pci_device = GetByAddress(found);
176             return pci_device.ReadDoubleWordPCI((uint)bar_no, offset);
177         }
178 
Reset()179         public override void Reset()
180         {
181         }
182         //private void TransferData(uint value)
183         //{
184         //        if (!children.Keys.Select (x => x.Number).Contains (slaveAddressForPacket))
185         //}
186 
Update()187         private void Update()
188         {
189         }
190 
191         private PCIInfo[] info;
192         bool[] _info;
193     }
194 }
195 
196