summaryrefslogtreecommitdiffstats
path: root/src/usr/pore/poreve/porevesrc/pibmem.C
blob: 46df8083a6133bb9d55ac63acc818b41d9da5d11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/pore/poreve/porevesrc/pibmem.C $                      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2012,2014              */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
// $Id: pibmem.C,v 1.4 2013/02/05 16:14:39 bcbrock Exp $

/// \file pibmem.C
/// \brief A model of the P8 "PIB-attached Memory"

#include "pibmem.H"

using namespace vsbe;

#ifndef VERBOSE
#define VERBOSE 0
#endif

////////////////////////////// Creators //////////////////////////////

Pibmem::Pibmem(const size_t i_memorySize) :
        iv_memorySize(i_memorySize)
{
        reset();
}


Pibmem::~Pibmem()
{
}


//////////////////////////// Manipulators ////////////////////////////


// Model direct and indirect access to memory and control registers.  Note
// that by specification, post inc/dec takes place even if the indirect access
// takes an error.

fapi::ReturnCode
Pibmem::operation(Transaction& io_transaction)
{
    fapi::ReturnCode rc;

    // The transaction is initially marked as successful, but may later pick
    // up PIB error codes.

    io_transaction.busError(ME_SUCCESS);


    // Split on direct vs. indirect accesses

    if (io_transaction.iv_offset < PIBMEM_CONTROL_BASE) {

        // These are simple direct PIB read/write of memory
 
        rc = memoryOperation(io_transaction, true);

        if (VERBOSE) {
            FAPI_DBG("PIBMEM : Direct to 0x%08x, %s 0x%016llx", 
                     io_transaction.iv_offset, 
                     ((io_transaction.iv_mode == ACCESS_MODE_WRITE) ?
                      "Write" : ((io_transaction.iv_mode == ACCESS_MODE_READ) ?
                                 "Read" : "Execute")),
                     io_transaction.iv_data);
        }

    } else {

        switch (io_transaction.iv_mode) {

        case ACCESS_MODE_READ:
        case ACCESS_MODE_EXECUTE:

            // Register reads and indirect memory reads

            switch (io_transaction.iv_offset) {

            case PIBMEM_CONTROL:
                io_transaction.iv_data = iv_control.value;
                break;

            case PIBMEM_ADDRESS:
                io_transaction.iv_data = iv_address.value;
                break;

            case PIBMEM_STATUS:
                io_transaction.iv_data = iv_status.value;
                break;

            case PIBMEM_RESET:
                io_transaction.iv_data = iv_reset.value;
                break;

            case PIBMEM_REPAIR:
                io_transaction.iv_data = iv_repair;
                break;

            case PIBMEM_DATA:
                rc = memoryOperation(io_transaction, false);
                break;

            case PIBMEM_DATA_INC:
                if (iv_control.fields.auto_pre_increment) {
                    incrAddress(1);
                }
                rc = memoryOperation(io_transaction, false);
                if (!iv_control.fields.auto_pre_increment) {
                    incrAddress(1);
                }                            
                break;

            case PIBMEM_DATA_DEC:
                if (!iv_control.fields.auto_post_decrement) {
                    incrAddress(-1);
                }
                rc = memoryOperation(io_transaction, false);
                if (iv_control.fields.auto_post_decrement) {
                    incrAddress(-1);
                }
                break;

            default:
                FAPI_ERR("PIBMEM: Can't read register at offset 0x%08x\n",
                         io_transaction.iv_offset);
                FAPI_SET_HWP_ERROR(rc, RC_POREVE_PIBMEM_CONTROL_ERROR);
                break;
            }

            break;

        case ACCESS_MODE_WRITE:

            // Register writes and indirect memory writes

            switch (io_transaction.iv_offset) {

            case PIBMEM_CONTROL:
                iv_control.value = 
                    io_transaction.iv_data & PIBMEM_CONTROL_DEFINED;
                break;

            case PIBMEM_ADDRESS:
                iv_address.value = 
                    io_transaction.iv_data & PIBMEM_ADDRESS_DEFINED;
                break;

            case PIBMEM_RESET:
                iv_reset.value = 
                    io_transaction.iv_data & PIBMEM_RESET_DEFINED;
                if (iv_reset.fields.reset_code == PIBMEM_RESET_CODE) {
                    reset();
                }
                break;

            case PIBMEM_REPAIR:
                // Behavior of this register is beyond the scope of the model
                iv_repair = io_transaction.iv_data;
                break;

            case PIBMEM_DATA:
                rc = memoryOperation(io_transaction, false);
                break;

            case PIBMEM_DATA_INC:
                if (iv_control.fields.auto_pre_increment) {
                    incrAddress(1);
                }
                rc = memoryOperation(io_transaction, false);
                if (!iv_control.fields.auto_pre_increment) {
                    incrAddress(1);
                }                            
                break;

            case PIBMEM_DATA_DEC:
                if (!iv_control.fields.auto_post_decrement) {
                    incrAddress(-1);
                }
                rc = memoryOperation(io_transaction, false);
                if (iv_control.fields.auto_post_decrement) {
                    incrAddress(-1);
                }
                break;

            default:
                FAPI_ERR("PIBMEM: Can't write register at offset 0x%08x\n",
                         io_transaction.iv_offset);
                FAPI_SET_HWP_ERROR(rc, RC_POREVE_PIBMEM_CONTROL_ERROR);
                break;
            }

            break;

        default:
            FAPI_ERR("PIBMEM: Transaction mode is illegal - %d\n", 
                     io_transaction.iv_mode);
            FAPI_SET_HWP_ERROR(rc, RC_POREVE_PIBMEM_CONTROL_ERROR);
            break;
        }
        
        if (VERBOSE) {
            FAPI_DBG("PIBMEM : Indirect to 0x%08x, %s 0x%016llx", 
                     io_transaction.iv_offset, 
                     ((io_transaction.iv_mode == ACCESS_MODE_WRITE) ?
                      "Write" : ((io_transaction.iv_mode == ACCESS_MODE_READ) ?
                                 "Read" : "Execute")),
                     io_transaction.iv_data);
        }

    }

    return rc;
}


////////////////////////// Implementation  //////////////////////////////////


// Note the differences in the error return codes for the error cases.  Asking
// for memory that does not exist in the hardware gives a normal return with a
// PIB 'address error' status code.  If the access was indirect then the
// PCB_PACKET_ERROR code is returned. Asking for memory that has not been
// mapped by the application yields a model error and a FAPI error.

fapi::ReturnCode 
Pibmem::memoryOperation(Transaction& io_transaction, 
                        const bool i_direct)
{
    fapi::ReturnCode rc;
    uint32_t saveAddress, saveOffset;

    if (i_direct) {
        if (io_transaction.iv_offset >= iv_memorySize) {

            iv_status.fields.addr_invalid = 1;
            if (io_transaction.iv_mode == ACCESS_MODE_WRITE) {
                iv_status.fields.write_invalid = 1;
            } else {
                iv_status.fields.read_invalid = 1;
            }
            ((PibTransaction&)io_transaction).iv_pcbReturnCode = 
                PCB_ADDRESS_ERROR;

        } else {

            rc = PibMemory::operation(io_transaction);

            if (rc) {
                FAPI_ERR("The previous error was from a direct "
                         "PIBMEM operation to the indicated address");
            }
        }

    } else {

        if (io_transaction.iv_offset >= iv_memorySize) {
        
            iv_status.fields.bad_array_address = 1;
            ((PibTransaction&)io_transaction).iv_pcbReturnCode = 
                PCB_PACKET_ERROR;
        } else {

            saveAddress = io_transaction.iv_address;
            saveOffset = io_transaction.iv_offset;

            io_transaction.iv_address = iv_address.fields.address_pointer;
            io_transaction.iv_offset = iv_address.fields.address_pointer;

            rc = PibMemory::operation(io_transaction);

            io_transaction.iv_address = saveAddress;
            io_transaction.iv_offset = saveOffset;

            if (rc) {
                FAPI_ERR("The previous error was from a PIBMEM operation "
                         "targeting the indicated address.\n"
                         "The operation was issued "
                         "indirectly through the PIBMEM control "
                         "register 0x%08x",
                         saveAddress);
            }
        }
    }

    return rc;
}


void
Pibmem::incrAddress(const int i_incr)
{
    iv_address.fields.address_pointer = 
        iv_address.fields.address_pointer + i_incr;
}


void
Pibmem::reset() {
        iv_control.value = 0;
        iv_address.value = 0;
        iv_status.value = 0;
        iv_reset.value = 0;
        iv_data = 0;
        iv_dataInc = 0;
        iv_dataDec = 0;
        iv_repair = 0;

        // The reset state (and subsequent status reads) show the FSM idle
        // state

        iv_status.fields.fsm_present_state = PIBMEM_FSM_IDLE;
}

/* Local Variables: */
/* c-basic-offset: 4 */
/* End: */
OpenPOWER on IntegriCloud