/[pearpc]/src/io/pci/pci.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/io/pci/pci.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (show annotations)
Wed Sep 5 18:04:11 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 14850 byte(s)
another tracer fix
1 /*
2 * PearPC
3 * pci.cc
4 *
5 * Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <cstdlib>
22 #include <cstring>
23
24 #include "tools/data.h"
25 #include "system/arch/sysendian.h"
26 #include "cpu/cpu.h"
27 #include "cpu/debug.h"
28 #include "cpu/mem.h"
29 #include "debug/tracers.h"
30 #include "pci.h"
31
32 #define PCI_ADDRESS_ECD(v) ((v) & 0x80000000)
33 #define PCI_ADDRESS_BUS(v) (((v)>>16) & 0xff)
34 #define PCI_ADDRESS_UNIT(v) (((v)>>11) & 0x1f)
35 #define PCI_ADDRESS_FUNCT(v) (((v)>>8) & 7)
36 #define PCI_ADDRESS_REG(v) (((v)) & 0xfc)
37 #define PCI_ADDRESS_TYPE(v) ((v) & 3)
38
39 uint32 gPCI_Address;
40 uint32 gPCI_Data;
41 static uint32 gPCI_Data_LE;
42 Container *gPCI_Devices;
43
44 class PCI_Bridge: public PCI_Device {
45 public:
46 PCI_Bridge(const char *aName, uint8 aBus, uint8 aUnit)
47 :PCI_Device(aName, aBus, aUnit)
48 {
49 mIORegsCount = 2;
50 }
51
52 };
53
54 class PCI_BridgeHost: public PCI_Bridge {
55 public:
56 PCI_BridgeHost();
57 };
58
59 class PCI_BridgeP2P: public PCI_Bridge {
60 public:
61 PCI_BridgeP2P();
62 };
63
64 PCI_Device::PCI_Device(const char *aName, uint8 aBus, uint8 aUnit)
65 :Object()
66 {
67 mName = strdup(aName);
68 mUnit = aUnit;
69 mBus = aBus;
70 mIORegsCount = 6;
71 memset(&mConfig, 0, sizeof mConfig);
72 memset(&mAddress, 0, sizeof mAddress);
73 memset(&mPort, 0, sizeof mPort);
74 memset(&mIORegType, 0, sizeof mIORegType);
75 memset(&mIORegSize, 0, sizeof mIORegSize);
76 }
77
78 PCI_Device::~PCI_Device()
79 {
80 free(mName);
81 }
82
83 int PCI_Device::compareTo(const Object *obj) const
84 {
85 int busdelta = (int)mBus - (int)((PCI_Device*)obj)->mBus;
86 if (!busdelta) {
87 return (int)mUnit - (int)((PCI_Device*)obj)->mUnit;
88 }
89 return busdelta;
90 }
91
92 void PCI_Device::assignMemAddress(uint r, uint32 aAddress)
93 {
94 IO_PCI_TRACE("assign-address[mem]: %s: %d: %08x\n", mName, r, aAddress);
95 mAddress[r] = aAddress;
96 mConfig[0x4] |= 0x2; // Enable response in memory space
97 mConfig[0x10+4*r] = aAddress | mIORegType[r];
98 mConfig[0x11+4*r] = aAddress>>8;
99 mConfig[0x12+4*r] = aAddress>>16;
100 mConfig[0x13+4*r] = aAddress>>24;
101 }
102
103 void PCI_Device::assignIOPort(uint r, uint32 aPort)
104 {
105 IO_PCI_TRACE("assign-address[io]: %s: %d: %08x\n", mName, r, aPort);
106 mPort[r] = aPort;
107 mConfig[0x4] |= 0x1; // Enable response in io space
108 mConfig[0x10+4*r] = aPort | 1; // Mark as io address
109 mConfig[0x11+4*r] = aPort>>8;
110 mConfig[0x12+4*r] = aPort>>16;
111 mConfig[0x13+4*r] = aPort>>24;
112 }
113
114 bool PCI_Device::readMem(uint32 aAddress, uint32 &data, uint size)
115 {
116 for (uint i=0; i < mIORegsCount; i++) {
117 if ((mIORegType[i] & 1) == PCI_ADDRESS_SPACE_MEM
118 && aAddress >= mAddress[i] && aAddress < (mAddress[i] + mIORegSize[i])) {
119 if (!readDeviceMem(i, aAddress-mAddress[i], data, size)) {
120 IO_PCI_ERR("%s: reg: %d: %08x read unimpl.\n", mName, i, aAddress-mAddress[i]);
121 }
122 return true;
123 }
124 }
125 return false;
126 }
127
128 bool PCI_Device::readIO(uint32 aPort, uint32 &data, uint size)
129 {
130 for (uint i=0; i < mIORegsCount; i++) {
131 if (mIORegType[i] == PCI_ADDRESS_SPACE_IO
132 && aPort >= mPort[i] && aPort < (mPort[i] + mIORegSize[i])) {
133 if (!readDeviceIO(i, aPort-mPort[i], data, size)) {
134 IO_PCI_ERR("%s: reg: %d: %08x read(%d) unimpl.\n", mName, i, aPort-mPort[i], size);
135 }
136 return true;
137 }
138 }
139 return false;
140 }
141
142 bool PCI_Device::writeMem(uint32 aAddress, uint32 data, uint size)
143 {
144 for (uint i=0; i < mIORegsCount; i++) {
145 if ((mIORegType[i] & 1) == PCI_ADDRESS_SPACE_MEM
146 && aAddress >= mAddress[i] && aAddress < (mAddress[i] + mIORegSize[i])) {
147 if (!writeDeviceMem(i, aAddress-mAddress[i], data, size)) {
148 IO_PCI_ERR("%s: reg: %d: %08x write unimpl.\n", mName, i, aAddress-mAddress[i]);
149 }
150 return true;
151 }
152 }
153 return false;
154 }
155
156 bool PCI_Device::writeIO(uint32 aPort, uint32 data, uint size)
157 {
158 for (uint i=0; i < mIORegsCount; i++) {
159 if (mIORegType[i] == PCI_ADDRESS_SPACE_IO
160 && aPort >= mPort[i] && aPort < (mPort[i] + mIORegSize[i])) {
161 if (!writeDeviceIO(i, aPort-mPort[i], data, size)) {
162 IO_PCI_ERR("%s: reg: %d: %08x write(%d) unimpl.\n", mName, i, aPort-mPort[i], size);
163 }
164 return true;
165 }
166 }
167 return false;
168 }
169
170 bool PCI_Device::readDeviceMem(uint r, uint32 address, uint32 &data, uint size)
171 {
172 return false;
173 }
174
175 bool PCI_Device::readDeviceIO(uint r, uint32 io, uint32 &data, uint size)
176 {
177 return false;
178 }
179
180 bool PCI_Device::writeDeviceMem(uint r, uint32 address, uint32 data, uint size)
181 {
182 return false;
183 }
184
185 bool PCI_Device::writeDeviceIO(uint r, uint32 io, uint32 data, uint size)
186 {
187 return false;
188 }
189
190 void PCI_Device::readConfig(uint reg)
191 {
192 gPCI_Data = ppc_word_from_LE(*(uint32*)&(mConfig[reg]));
193 }
194
195 void PCI_Device::writeConfig(uint reg, int offset, int size)
196 {
197 if (reg >= 0x10 && reg < (4*mIORegsCount+0x10)) {
198 uint rreg = (reg-0x10) >> 2;
199 if (mIORegSize[rreg]) {
200 if (gPCI_Data != 0xffffffff && gPCI_Data != 0) {
201 if (mIORegType[rreg]==PCI_ADDRESS_SPACE_MEM) {
202 assignMemAddress(rreg, gPCI_Data & ~0xf);
203 } else {
204 assignIOPort(rreg, gPCI_Data & ~0x3);
205 }
206 }
207 if ((mIORegType[rreg] & 1) == PCI_ADDRESS_SPACE_MEM) {
208 uint32 x = 8;
209 for (int i=2; i<31; i++) {
210 gPCI_Data &= ~x;
211 x <<= 1;
212 if (x >= mIORegSize[rreg]) break;
213 }
214 gPCI_Data &= ~0xf;
215 } else {
216 uint32 x = 2;
217 for (int i=2; i<31; i++) {
218 gPCI_Data &= ~x;
219 x <<= 1;
220 if (x >= mIORegSize[rreg]) break;
221 }
222 gPCI_Data &= ~0x3;
223 }
224 gPCI_Data |= mIORegType[rreg];
225 }
226 }
227 *(uint32*)&(mConfig[reg]) = ppc_word_to_LE(gPCI_Data);
228 }
229
230 void PCI_Device::setCommand(uint16 command)
231 {
232 }
233
234 void PCI_Device::setStatus(uint16 status)
235 {
236 }
237
238 PCI_BridgeP2P::PCI_BridgeP2P()
239 :PCI_Bridge("pci-bridge-p2p", 0x00, 0x0d)
240 {
241 mConfig[0x00] = 0x11; // vendor ID
242 mConfig[0x01] = 0x10;
243 mConfig[0x02] = 0x26; // unit ID
244 mConfig[0x03] = 0x00;
245
246 mConfig[0x08] = 0x02; // revision
247 mConfig[0x09] = 0x00; // programming interface code
248 mConfig[0x0a] = 0x04; // pci2pci
249 mConfig[0x0b] = 0x06; // bridge
250
251 mConfig[0x0e] = 0x01; // header-type
252
253 mConfig[0x18] = 0x0; // primary bus number
254 mConfig[0x19] = 0x1; // secondary bus number
255 mConfig[0x1a] = 0x1; // highest bus number behind bridge
256 mConfig[0x1c] = 0x10; // i/o base behind bridge
257 mConfig[0x1d] = 0x20; // i/o limit
258
259 mConfig[0x20] = 0x80; // memory base
260 mConfig[0x21] = 0x80; // memory base
261 mConfig[0x22] = 0x90; // memory limit
262 mConfig[0x23] = 0x80; // memory limit
263
264 mConfig[0x24] = 0x00; // prefetch memory base
265 mConfig[0x25] = 0x84; // prefetch memory base
266 mConfig[0x26] = 0x00; // prefetch memory limit
267 mConfig[0x27] = 0x85; // prefetch memory limit
268
269 mConfig[0x32] = 0x00; // upper io limit
270 }
271
272 PCI_BridgeHost::PCI_BridgeHost()
273 :PCI_Bridge("pci-bridge-host", 0x00, 0x0e)
274 {
275 mConfig[0x00] = 0x11; // vendor ID
276 mConfig[0x01] = 0x10;
277 mConfig[0x02] = 0x26; // unit ID
278 mConfig[0x03] = 0x00;
279
280 mConfig[0x08] = 0x00; // revision
281 mConfig[0x09] = 0x01;
282 mConfig[0x0a] = 0x04; // host
283 mConfig[0x0b] = 0x06; // bridge
284
285 mConfig[0x0e] = 0x01; // header-type
286
287 mConfig[0x18] = 0x0; // primary bus number
288 mConfig[0x19] = 0x1; // secondary bus number
289 mConfig[0x1a] = 0x0; // highest bus number behind bridge
290 mConfig[0x1c] = 0x0; // i/o behind bridge
291
292 mConfig[0x20] = 0x0; // memory base
293 mConfig[0x21] = 0x0; // memory base
294 mConfig[0x22] = 0x1; // memory limit
295 mConfig[0x23] = 0x0; // memory limit
296
297 mConfig[0x24] = 0x0; // prefetch memory base
298 mConfig[0x25] = 0x0; // prefetch memory base
299 mConfig[0x26] = 0x0; // prefetch memory limit
300 mConfig[0x27] = 0x0; // prefetch memory limit
301 }
302
303 /**************************************************************************************
304 *
305 */
306
307 static void pci_config_read_write(bool write, int offset, int size)
308 {
309 IO_PCI_TRACE("ecd: %d bus: 0x%02x unit: 0x%02x funct: 0x%02x reg: 0x%02x type: %d\n",
310 PCI_ADDRESS_ECD(gPCI_Address)?1:0, PCI_ADDRESS_BUS(gPCI_Address),
311 PCI_ADDRESS_UNIT(gPCI_Address), PCI_ADDRESS_FUNCT(gPCI_Address),
312 PCI_ADDRESS_REG(gPCI_Address),PCI_ADDRESS_TYPE(gPCI_Address));
313
314 if (PCI_ADDRESS_FUNCT(gPCI_Address)) {
315 IO_PCI_ERR("PCI: func != 0\n");
316 }
317 if (PCI_ADDRESS_TYPE(gPCI_Address)) {
318 IO_PCI_ERR("PCI: type != 0\n");
319 }
320 if (PCI_ADDRESS_ECD(gPCI_Address)) {
321 PCI_Device empty("", PCI_ADDRESS_BUS(gPCI_Address), PCI_ADDRESS_UNIT(gPCI_Address));
322 PCI_Device *p = (PCI_Device*)gPCI_Devices->get(gPCI_Devices->find(&empty));
323 if (!p) {
324 if (!write) gPCI_Data = 0;
325 return;
326 }
327 if (write) {
328 gPCI_Data = ppc_word_from_LE(gPCI_Data_LE);
329 p->writeConfig(PCI_ADDRESS_REG(gPCI_Address), offset, size);
330 } else {
331 p->readConfig(PCI_ADDRESS_REG(gPCI_Address));
332 gPCI_Data_LE = ppc_word_to_LE(gPCI_Data);
333 }
334 } else {
335 IO_PCI_WARN("PCI: ecd != 1\n");
336 }
337 }
338
339 void pci_write(uint32 addr, uint32 data, int size)
340 {
341 if (addr != IO_PCI_PA_START) IO_PCI_TRACE("write (%d) @%08x: %08x (from %08x, %08x)\n", size, addr, data, ppc_cpu_get_pc(0), ppc_cpu_get_lr(0));
342 addr -= IO_PCI_PA_START;
343 switch (addr) {
344 case 0:
345 case 0xcf8:
346 if (size != 4) {
347 IO_PCI_ERR("pci bla\n");
348 }
349 gPCI_Address = data;
350 pci_config_read_write(false, 0, 4);
351 return;
352 case 0x200000:
353 case 0x200cfc:
354 if (size == 1) {
355 void *p = &gPCI_Data_LE;
356 *(uint8 *)p = data;
357 pci_config_read_write(true, 0, 1);
358 return;
359 }
360 if (size == 2) {
361 void *p = &gPCI_Data_LE;
362 *(uint16 *)p = ppc_half_to_LE(data);
363 pci_config_read_write(true, 0, 2);
364 return;
365 }
366 if (size != 4) {
367 IO_PCI_ERR("pci bla\n");
368 }
369 gPCI_Data_LE = ppc_word_to_LE(data);
370 pci_config_read_write(true, 0, 4);
371 return;
372 case 0x200001:
373 case 0x200cfd: {
374 if (size != 1) {
375 IO_PCI_ERR("pci bla\n");
376 }
377 char *p = (char*)&gPCI_Data_LE;
378 *(uint8 *)(p+1) = data;
379 pci_config_read_write(true, 1, 1);
380 return;
381 }
382 case 0x200002:
383 case 0x200cfe: {
384 if (size > 2) {
385 IO_PCI_ERR("pci bla\n");
386 }
387 if (size == 1) {
388 char *p = (char *)&gPCI_Data_LE;
389 *(uint8 *)(p+2) = data;
390 pci_config_read_write(true, 2, 1);
391 return;
392 }
393 char *p = (char *)&gPCI_Data_LE;
394 *(uint16 *)(p+2) = ppc_half_to_LE(data);
395 pci_config_read_write(true, 2, 2);
396 return;
397 }
398 case 0x200003:
399 case 0x200cff: {
400 if (size != 1) {
401 IO_PCI_ERR("pci bla\n");
402 }
403 char *p = (char *)&gPCI_Data_LE;
404 *(uint8 *)(p+3) = data;
405 pci_config_read_write(true, 3, 1);
406 return;
407 }
408 }
409 SINGLESTEP("unknown service\n");
410 }
411
412 void pci_read(uint32 addr, uint32 &data, int size)
413 {
414 // SINGLESTEP("usdf\n");
415 if (addr != IO_PCI_PA_START) IO_PCI_TRACE("read (%d) @%08x (from %08x, lr: %08x) -> \n", size, addr, ppc_cpu_get_pc(0), ppc_cpu_get_lr(0));
416 addr -= IO_PCI_PA_START;
417 switch (addr) {
418 case 0:
419 case 0xcf8:
420 data = gPCI_Address;
421 return;
422 case 0x200000:
423 case 0x200cfc:
424 if (size == 1) {
425 void *p = &gPCI_Data_LE;
426 data = *(uint8 *)p;
427 IO_PCI_TRACE("%02x\n", data);
428 return;
429 }
430 if (size == 2) {
431 void *p = &gPCI_Data_LE;
432 data = ppc_half_from_LE(*(uint16 *)p);
433 IO_PCI_TRACE("%04x\n", data);
434 return;
435 }
436 if (size != 4) {
437 IO_PCI_ERR("pci bla\n");
438 }
439 data = ppc_word_from_LE(gPCI_Data_LE);
440 IO_PCI_TRACE("%08x\n", data);
441 return;
442 case 0x200001:
443 case 0x200cfd: {
444 if (size != 1) {
445 IO_PCI_ERR("pci bla\n");
446 }
447 char *p = (char*)&gPCI_Data_LE;
448 data = *(uint8 *)(p+1);
449 IO_PCI_TRACE("%02x\n", data);
450 return;
451 }
452 case 0x200002:
453 case 0x200cfe: {
454 if (size > 2) {
455 IO_PCI_ERR("pci bla\n");
456 }
457 if (size==1) {
458 char *p = (char*)&gPCI_Data_LE;
459 data = *(uint8 *)(p+2);
460 IO_PCI_TRACE("%02x\n", data);
461 return;
462 }
463 char *p = (char*)&gPCI_Data_LE;
464 data = ppc_half_from_LE(*(uint16 *)(p+2));
465 IO_PCI_TRACE("%04x\n", data);
466 return;
467 }
468 case 0x200003:
469 case 0x200cff:
470 if (size != 1) {
471 IO_PCI_ERR("pci bla\n");
472 }
473 char *p = (char*)&gPCI_Data_LE;
474 data = *(uint8 *)(p+3);
475 IO_PCI_TRACE("%02x\n", data);
476 return;
477 }
478 data = 0;
479 SINGLESTEP("%08x unknown service\n", addr);
480 }
481
482 bool isa_read(uint32 addr, uint32 &data, int size)
483 {
484 // Translate address into port
485 addr -= IO_ISA_PA_START;
486 ObjHandle oh = gPCI_Devices->findFirst();
487 while (oh != InvObjHandle) {
488 PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
489 if (pd->readIO(addr, data, size)) {
490 return true;
491 }
492 oh = gPCI_Devices->findNext(oh);
493 }
494 data = 0;
495 // gSinglestep = true;
496 IO_PCI_WARN("port %08x not registered! (for read)\n", addr);
497 return false;
498 }
499
500 bool isa_write(uint32 addr, uint32 data, int size)
501 {
502 // Translate address into port
503 addr -= IO_ISA_PA_START;
504 ObjHandle oh = gPCI_Devices->findFirst();
505 while (oh != InvObjHandle) {
506 PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
507 if (pd->writeIO(addr, data, size)) {
508 return true;
509 }
510 oh = gPCI_Devices->findNext(oh);
511 }
512 // gSinglestep = true;
513 IO_PCI_WARN("port %08x not registered! (for write)\n", addr);
514 return false;
515 }
516
517 bool pci_write_device(uint32 addr, uint32 data, int size)
518 {
519 IO_PCI_TRACE("write DEVICE (%d) @%08x %08x (from %08x, lr: %08x)\n", size, addr, data, ppc_cpu_get_pc(0), ppc_cpu_get_lr(0));
520 ObjHandle oh = gPCI_Devices->findFirst();
521 while (oh != InvObjHandle) {
522 PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
523 if (pd->writeMem(addr, data, size)) {
524 return true;
525 }
526 oh = gPCI_Devices->findNext(oh);
527 }
528 return false;
529 }
530
531 bool pci_read_device(uint32 addr, uint32 &data, int size)
532 {
533 IO_PCI_TRACE("read DEVICE (%d) @%08x (from %08x, lr: %08x)\n", size, addr, ppc_cpu_get_pc(0), ppc_cpu_get_lr(0));
534 ObjHandle oh = gPCI_Devices->findFirst();
535 while (oh != InvObjHandle) {
536 PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
537 if (pd->readMem(addr, data, size)) {
538 IO_PCI_TRACE("->%08x\n", data);
539 return true;
540 }
541 oh = gPCI_Devices->findNext(oh);
542 }
543 data = 0;
544 return false;
545 }
546
547 // PCI devices
548 #include "io/graphic/gcard.h"
549 #include "io/ide/ide.h"
550 #include "io/macio/macio.h"
551 #include "io/3c90x/3c90x.h"
552 #include "io/rtl8139/rtl8139.h"
553 #include "io/usb/usb.h"
554 #include "io/serial/serial.h"
555
556 void pci_init()
557 {
558 gPCI_Devices = new AVLTree(true);
559 gPCI_Devices->insert(new PCI_BridgeP2P());
560 // gPCI_Devices->insert(new PCI_BridgeHost());
561
562 gcard_init();
563 ide_init();
564 macio_init();
565 _3c90x_init();
566 rtl8139_init();
567 usb_init();
568 serial_init();
569 }
570
571 void pci_done()
572 {
573 serial_done();
574 usb_done();
575 rtl8139_done();
576 _3c90x_done();
577 macio_done();
578 ide_done();
579 gcard_done();
580
581 delete gPCI_Devices;
582 }
583
584 void pci_init_config()
585 {
586 gcard_init_config();
587 ide_init_config();
588 macio_init_config();
589 _3c90x_init_config();
590 rtl8139_init_config();
591 usb_init_config();
592 serial_init_config();
593 }

  ViewVC Help
Powered by ViewVC 1.1.26