tsunami_pchip.cc revision 2539
1/*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file
30 * Tsunami PChip (pci)
31 */
32
33#include <deque>
34#include <string>
35#include <vector>
36
37#include "arch/alpha/ev5.hh"
38#include "base/trace.hh"
39#include "dev/tsunami_pchip.hh"
40#include "dev/tsunamireg.h"
41#include "dev/tsunami.hh"
42#include "mem/bus/bus.hh"
43#include "mem/bus/pio_interface.hh"
44#include "mem/bus/pio_interface_impl.hh"
45#include "mem/functional/memory_control.hh"
46#include "mem/functional/physical.hh"
47#include "sim/builder.hh"
48#include "sim/system.hh"
49
50using namespace std;
51//Should this be AlphaISA?
52using namespace TheISA;
53
54TsunamiPChip::TsunamiPChip(Params *p)
55: BasicPioDevice(p),
56{
57    pioSize = 0xfff;
58
59    for (int i = 0; i < 4; i++) {
60        wsba[i] = 0;
61        wsm[i] = 0;
62        tba[i] = 0;
63    }
64
65    // initialize pchip control register
66    pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36);
67
68    //Set back pointer in tsunami
69    p->tsunami->pchip = this;
70}
71
72Tick
73TsunamiPChip::read(Packet &pkt)
74{
75    assert(pkt.result == Unknown);
76    assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
77
78    pkt.time = curTick + pioDelay;
79    Addr daddr = pkt.addr - pioAddr;
80
81    uint64_t *data64;
82
83    if (!pkt.data) {
84        data64 = new uint64_t;
85        pkt.data = (uint8_t*)data64;
86    } else
87        data64 = (uint64_t*)pkt.data;
88
89    DPRINTF(Tsunami, "read  va=%#x size=%d\n", pkt.addr, pkt.size);
90
91    switch(daddr) {
92      case TSDEV_PC_WSBA0:
93            *data64 = wsba[0];
94            break;
95      case TSDEV_PC_WSBA1:
96            *data64 = wsba[1];
97            break;
98      case TSDEV_PC_WSBA2:
99            *data64 = wsba[2];
100            break;
101      case TSDEV_PC_WSBA3:
102            *data64 = wsba[3];
103            break;
104      case TSDEV_PC_WSM0:
105            *data64 = wsm[0];
106            break;
107      case TSDEV_PC_WSM1:
108            *data64 = wsm[1];
109            break;
110      case TSDEV_PC_WSM2:
111            *data64 = wsm[2];
112            break;
113      case TSDEV_PC_WSM3:
114            *data64 = wsm[3];
115            break;
116      case TSDEV_PC_TBA0:
117            *data64 = tba[0];
118            break;
119      case TSDEV_PC_TBA1:
120            *data64 = tba[1];
121            break;
122      case TSDEV_PC_TBA2:
123            *data64 = tba[2];
124            break;
125      case Tbreak;
126            *data64 = tba[3];
127            break;
128      case TSDEV_PC_PCTL:
129            *data64 = pctl;
130            break;
131      case TSDEV_PC_PLAT:
132            panic("PC_PLAT not implemented\n");
133      case TSDEV_PC_RES:
134            panic("PC_RES not implemented\n");
135      case TSDEV_PC_PERROR:
136            *data64 = 0x00;
137            break;
138      case TSDEV_PC_PERRMASK:
139            *data64 = 0x00;
140            break;
141      case TSDEV_PC_PERRSET:
142            panic("PC_PERRSET not implemented\n");
143      case TSDEV_PC_TLBIV:
144            panic("PC_TLBIV not implemented\n");
145      case TSDEV_PC_TLBIA:
146            *data64 = 0x00; // shouldn't be readable, but linux
147            break;
148      case TSDEV_PC_PMONCTL:
149            panic("PC_PMONCTL not implemented\n");
150      case TSDEV_PC_PMONCNT:
151            panic("PC_PMONCTN not implemented\n");
152      default:
153          panic("Default in PChip Read reached reading 0x%x\n", daddr);
154    }
155    pkt.result = Success;
156    return pioDelay;
157
158}
159
160Fault
161TsunamiPChip::write(Packet &pkt)
162{
163    pkt.time = curTick + pioDelay;
164
165    assert(pkt.result == Unknown);
166    assert(pkt.addr >= pioAddr && pkt.addr < pioAddr + pioSize);
167    Addr daddr = pkt.addr - pioAddr;
168
169    uint64_t val = *(uint64_t *)pkt.data;
170    assert(pkt.size == sizeof(uint64_t));
171
172    DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt.addr, pkt.size);
173
174    switch(daddr) {
175        case TSDEV_PC_WSBA0:
176              wsba[0] = data64;
177              break;
178        case TSDEV_PC_WSBA1:
179              wsba[1] = data64;
180              break;
181        case TSDEV_PC_WSBA2:
182              wsba[2] = data64;
183              break;
184        case TSDEV_PC_WSBA3:
185              wsba[3] = data64;
186              break;
187        case TSDEV_PC_WSM0:
188              wsm[0] = data64;
189              break;
190        case TSDEV_PC_WSM1:
191              wsm[1] = data64;
192              break;
193        case TSDEV_PC_WSM2:
194              wsm[2] = data64;
195              break;
196        case TSDEV_PC_WSM3:
197              wsm[3] = data64;
198              break;
199        case TSDEV_PC_TBA0:
200              tba[0] = data64;
201              break;
202        case TSDEV_PC_TBA1:
203              tba[1] = data64;
204              break;
205        case TSDEV_PC_TBA2:
206              tba[2] = data64;
207              break;
208        case TSDEV_PC_TBA3:
209              tba[3] = data64;
210              break;
211        case TSDEV_PC_PCTL:
212              pctl = data64;
213              break;
214        case TSDEV_PC_PLAT:
215              panic("PC_PLAT not implemented\n");
216        case TSDEV_PC_RES:
217              panic("PC_RES not implemented\n");
218        case TSDEV_PC_PERROR:
219              break;
220        case TSDEV_PC_PERRMASK:
221              panic("PC_PERRMASK not implemented\n");
222        case TSDEV_PC_PERRSET:
223              panic("PC_PERRSET not implemented\n");
224        case TSDEV_PC_TLBIV:
225              panic("PC_TLBIV not implemented\n");
226        case TSDEV_PC_TLBIA:
227              break; // value ignored, supposted to invalidate SG TLB
228        case TSDEV_PC_PMONCTL:
229              panic("PC_PMONCTL not implemented\n");
230        case TSDEV_PC_PMONCNT:
231              panic("PC_PMONCTN not implemented\n");
232        default:
233            panic("Default in PChip Read reached reading 0x%x\n", daddr);
234
235    } // uint64_t
236
237    pkt.result = Success;
238    return pioDelay;
239}
240
241#define DMA_ADDR_MASK ULL(0x3ffffffff)
242
243Addr
244TsunamiPChip::translatePciToDma(Addr busAddr)
245{
246    // compare the address to the window base registers
247    uint64_t tbaMask = 0;
248    uint64_t baMask = 0;
249
250    uint64_t windowMask = 0;
251    uint64_t windowBase = 0;
252
253    uint64_t pteEntry = 0;
254
255    Addr pteAddr;
256    Addr dmaAddr;
257
258#if 0
259    DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr);
260    for (int i = 0; i < 4; i++) {
261        DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n",
262                i, wsba[i], wsm[i]);
263
264        windowBase = wsba[i];
265        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
266
267        if ((busAddr & windowMask) == (windowBase & windowMask)) {
268            DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n",
269                    i, windowBase, windowMask, (busAddr & windowMask),
270                    (windowBase & windowMask));
271        }
272    }
273#endif
274
275    for (int i = 0; i < 4; i++) {
276
277        windowBase = wsba[i];
278        windowMask = ~wsm[i] & (ULL(0xfff) << 20);
279
280        if ((busAddr & windowMask) == (windowBase & windowMask)) {
281
282            if (wsba[i] & 0x1) {   // see if enabled
283                if (wsba[i] & 0x2) { // see if SG bit is set
284                    /** @todo
285                        This currently is faked by just doing a direct
286                        read from memory, however, to be realistic, this
287                        needs to actually do a bus transaction.  The process
288                        is explained in the tsunami documentation on page
289                        10-12 and basically munges the address to look up a
290                        PTE from a table in memory and then uses that mapping
291                        to create an address for the SG page
292                    */
293
294                    tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff));
295                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13);
296                    pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10);
297
298                    pioPort->readBlob(&pteEntry, pteAddr, sizeof(uint64_t));
299
300                    dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff));
301
302                } else {
303                    baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff);
304                    tbaMask = ~baMask;
305                    dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask);
306                }
307
308                return (dmaAddr & DMA_ADDR_MASK);
309            }
310        }
311    }
312
313    // if no match was found, then return the original address
314    return busAddr;
315}
316
317void
318TsunamiPChip::serialize(std::ostream &os)
319{
320    SERIALIZE_SCALAR(pctl);
321    SERIALIZE_ARRAY(wsba, 4);
322    SERIALIZE_ARRAY(wsm, 4);
323    SERIALIZE_ARRAY(tba, 4);
324}
325
326void
327TsunamiPChip::unserialize(Checkpoint *cp, const std::string &section)
328{
329    UNSERIALIZE_SCALAR(pctl);
330    UNSERIALIZE_ARRAY(wsba, 4);
331    UNSERIALIZE_ARRAY(wsm, 4);
332    UNSERIALIZE_ARRAY(tba, 4);
333}
334
335Tick
336TsunamiPChip::cacheAccess(MemReqPtr &req)
337{
338    return curTick + pioLatency;
339}
340
341BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
342
343    Param<Addr> pio_addr;
344    Param<Tick> pio_latency;
345    SimObjectParam<Platform *> platform;
346    SimObjectParam<System *> system;
347    SimObjectParam<Tsunami *> tsunami;
348
349END_DECLARE_SIM_OBJECT_PARAMS(TsunamiPChip)
350
351BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
352
353    INIT_PARAM(pio_addr, "Device Address"),
354    INIT_PARAM(pio_latency, "Programmed IO latency"),
355    INIT_PARAM(platform, "platform"),
356    INIT_PARAM(system, "system object"),
357    INIT_PARAM(tsunami, "Tsunami")
358
359END_INIT_SIM_OBJECT_PARAMS(TsunamiPChip)
360
361CREATE_SIM_OBJECT(TsunamiPChip)
362{
363    TsunamiPChip::Params *p = new TsunamiPChip::Params;
364    p->name = getInstanceName();
365    p->pio_addr = pio_addr;
366    p->pio_delay = pio_latency;
367    p->platform = platform;
368    p->system = system;
369    p->tsunami = tsunami;
370    return new TsunamiPChip(p);
371}
372
373REGISTER_SIM_OBJECT("TsunamiPChip", TsunamiPChip)
374