Check.cc revision 7823:dac01f14f20f
1/*
2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
3 * Copyright (c) 2009 Advanced Micro Devices, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "cpu/testers/rubytest/Check.hh"
31#include "mem/ruby/common/SubBlock.hh"
32#include "mem/ruby/system/Sequencer.hh"
33#include "mem/ruby/system/System.hh"
34
35typedef RubyTester::SenderState SenderState;
36
37Check::Check(const Address& address, const Address& pc,
38             int _num_cpu_sequencers, RubyTester* _tester)
39    : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
40{
41    m_status = TesterStatus_Idle;
42
43    pickValue();
44    pickInitiatingNode();
45    changeAddress(address);
46    m_pc = pc;
47    m_access_mode = AccessModeType(random() % AccessModeType_NUM);
48    m_store_count = 0;
49}
50
51void
52Check::initiate()
53{
54    DPRINTF(RubyTest, "initiating\n");
55    debugPrint();
56
57    // currently no protocols support prefetches
58    if (false && (random() & 0xf) == 0) {
59        initiatePrefetch(); // Prefetch from random processor
60    }
61
62    if (m_status == TesterStatus_Idle) {
63        initiateAction();
64    } else if (m_status == TesterStatus_Ready) {
65        initiateCheck();
66    } else {
67        // Pending - do nothing
68        DPRINTF(RubyTest,
69                "initiating action/check - failed: action/check is pending\n");
70    }
71}
72
73void
74Check::initiatePrefetch()
75{
76    DPRINTF(RubyTest, "initiating prefetch\n");
77
78    int index = random() % m_num_cpu_sequencers;
79    RubyTester::CpuPort* port =
80        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
81
82    Request::Flags flags;
83    flags.set(Request::PREFETCH);
84
85    Packet::Command cmd;
86
87    // 1 in 8 chance this will be an exclusive prefetch
88    if ((random() & 0x7) != 0) {
89        cmd = MemCmd::ReadReq;
90
91        // 50% chance that the request will be an instruction fetch
92        if ((random() & 0x1) == 0) {
93            flags.set(Request::INST_FETCH);
94        }
95    } else {
96        cmd = MemCmd::WriteReq;
97        flags.set(Request::PF_EXCLUSIVE);
98    }
99
100    // Prefetches are assumed to be 0 sized
101    Request *req = new Request(m_address.getAddress(), 0, flags, curTick(),
102                               m_pc.getAddress());
103
104    PacketPtr pkt = new Packet(req, cmd, port->idx);
105
106    // push the subblock onto the sender state.  The sequencer will
107    // update the subblock on the return
108    pkt->senderState =
109        new SenderState(m_address, req->getSize(), pkt->senderState);
110
111    if (port->sendTiming(pkt)) {
112        DPRINTF(RubyTest, "successfully initiated prefetch.\n");
113    } else {
114        // If the packet did not issue, must delete
115        SenderState* senderState =  safe_cast<SenderState*>(pkt->senderState);
116        pkt->senderState = senderState->saved;
117        delete senderState;
118        delete pkt->req;
119        delete pkt;
120
121        DPRINTF(RubyTest,
122                "prefetch initiation failed because Port was busy.\n");
123    }
124}
125
126void
127Check::initiateAction()
128{
129    DPRINTF(RubyTest, "initiating Action\n");
130    assert(m_status == TesterStatus_Idle);
131
132    int index = random() % m_num_cpu_sequencers;
133    RubyTester::CpuPort* port =
134        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
135
136    Request::Flags flags;
137
138    // Create the particular address for the next byte to be written
139    Address writeAddr(m_address.getAddress() + m_store_count);
140
141    // Stores are assumed to be 1 byte-sized
142    Request *req = new Request(writeAddr.getAddress(), 1, flags, curTick(),
143                               m_pc.getAddress());
144
145    Packet::Command cmd;
146
147    // 1 out of 8 chance, issue an atomic rather than a write
148    // if ((random() & 0x7) == 0) {
149    //     cmd = MemCmd::SwapReq;
150    // } else {
151    cmd = MemCmd::WriteReq;
152    // }
153
154    PacketPtr pkt = new Packet(req, cmd, port->idx);
155    uint8_t* writeData = new uint8_t;
156    *writeData = m_value + m_store_count;
157    pkt->dataDynamic(writeData);
158
159    DPRINTF(RubyTest, "data 0x%x check 0x%x\n",
160            *(pkt->getPtr<uint8_t>()), *writeData);
161
162    // push the subblock onto the sender state.  The sequencer will
163    // update the subblock on the return
164    pkt->senderState =
165        new SenderState(writeAddr, req->getSize(), pkt->senderState);
166
167    if (port->sendTiming(pkt)) {
168        DPRINTF(RubyTest, "initiating action - successful\n");
169        DPRINTF(RubyTest, "status before action update: %s\n",
170                (TesterStatus_to_string(m_status)).c_str());
171        m_status = TesterStatus_Action_Pending;
172    } else {
173        // If the packet did not issue, must delete
174        // Note: No need to delete the data, the packet destructor
175        // will delete it
176        SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
177        pkt->senderState = senderState->saved;
178        delete senderState;
179        delete pkt->req;
180        delete pkt;
181
182        DPRINTF(RubyTest, "failed to initiate action - sequencer not ready\n");
183    }
184
185    DPRINTF(RubyTest, "status after action update: %s\n",
186            (TesterStatus_to_string(m_status)).c_str());
187}
188
189void
190Check::initiateCheck()
191{
192    DPRINTF(RubyTest, "Initiating Check\n");
193    assert(m_status == TesterStatus_Ready);
194
195    int index = random() % m_num_cpu_sequencers;
196    RubyTester::CpuPort* port =
197        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
198
199    Request::Flags flags;
200
201    // 50% chance that the request will be an instruction fetch
202    if ((random() & 0x1) == 0) {
203        flags.set(Request::INST_FETCH);
204    }
205
206    // Checks are sized depending on the number of bytes written
207    Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags,
208                               curTick(), m_pc.getAddress());
209
210    PacketPtr pkt = new Packet(req, MemCmd::ReadReq, port->idx);
211    uint8_t* dataArray = new uint8_t[CHECK_SIZE];
212    pkt->dataDynamicArray(dataArray);
213
214    // push the subblock onto the sender state.  The sequencer will
215    // update the subblock on the return
216    pkt->senderState =
217        new SenderState(m_address, req->getSize(), pkt->senderState);
218
219    if (port->sendTiming(pkt)) {
220        DPRINTF(RubyTest, "initiating check - successful\n");
221        DPRINTF(RubyTest, "status before check update: %s\n",
222                TesterStatus_to_string(m_status).c_str());
223        m_status = TesterStatus_Check_Pending;
224    } else {
225        // If the packet did not issue, must delete
226        // Note: No need to delete the data, the packet destructor
227        // will delete it
228        SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
229        pkt->senderState = senderState->saved;
230        delete senderState;
231        delete pkt->req;
232        delete pkt;
233
234        DPRINTF(RubyTest, "failed to initiate check - cpu port not ready\n");
235    }
236
237    DPRINTF(RubyTest, "status after check update: %s\n",
238            TesterStatus_to_string(m_status).c_str());
239}
240
241void
242Check::performCallback(NodeID proc, SubBlock* data)
243{
244    Address address = data->getAddress();
245
246    // This isn't exactly right since we now have multi-byte checks
247    //  assert(getAddress() == address);
248
249    assert(getAddress().getLineAddress() == address.getLineAddress());
250    assert(data != NULL);
251
252    DPRINTF(RubyTest, "RubyTester Callback\n");
253    debugPrint();
254
255    if (m_status == TesterStatus_Action_Pending) {
256        DPRINTF(RubyTest, "Action callback write value: %d, currently %d\n",
257                (m_value + m_store_count), data->getByte(0));
258        // Perform store one byte at a time
259        data->setByte(0, (m_value + m_store_count));
260        m_store_count++;
261        if (m_store_count == CHECK_SIZE) {
262            m_status = TesterStatus_Ready;
263        } else {
264            m_status = TesterStatus_Idle;
265        }
266        DPRINTF(RubyTest, "Action callback return data now %d\n",
267                data->getByte(0));
268    } else if (m_status == TesterStatus_Check_Pending) {
269        DPRINTF(RubyTest, "Check callback\n");
270        // Perform load/check
271        for (int byte_number=0; byte_number<CHECK_SIZE; byte_number++) {
272            if (uint8(m_value + byte_number) != data->getByte(byte_number)) {
273                panic("Action/check failure: proc: %d address: %s data: %s "
274                      "byte_number: %d m_value+byte_number: %d byte: %d %s"
275                      "Time: %d\n",
276                      proc, address, data, byte_number,
277                      (int)m_value + byte_number,
278                      (int)data->getByte(byte_number), *this,
279                      g_eventQueue_ptr->getTime());
280            }
281        }
282        DPRINTF(RubyTest, "Action/check success\n");
283        debugPrint();
284
285        // successful check complete, increment complete
286        m_tester_ptr->incrementCheckCompletions();
287
288        m_status = TesterStatus_Idle;
289        pickValue();
290
291    } else {
292        panic("Unexpected TesterStatus: %s proc: %d data: %s m_status: %s "
293              "time: %d\n",
294              *this, proc, data, m_status, g_eventQueue_ptr->getTime());
295    }
296
297    DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc,
298            getAddress().getLineAddress());
299    DPRINTF(RubyTest, "Callback done\n");
300    debugPrint();
301}
302
303void
304Check::changeAddress(const Address& address)
305{
306    assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready);
307    m_status = TesterStatus_Idle;
308    m_address = address;
309    m_store_count = 0;
310}
311
312void
313Check::pickValue()
314{
315    assert(m_status == TesterStatus_Idle);
316    m_status = TesterStatus_Idle;
317    m_value = random() & 0xff; // One byte
318    m_store_count = 0;
319}
320
321void
322Check::pickInitiatingNode()
323{
324    assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready);
325    m_status = TesterStatus_Idle;
326    m_initiatingNode = (random() % m_num_cpu_sequencers);
327    DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
328    m_store_count = 0;
329}
330
331void
332Check::print(std::ostream& out) const
333{
334    out << "["
335        << m_address << ", value: "
336        << (int)m_value << ", status: "
337        << m_status << ", initiating node: "
338        << m_initiatingNode << ", store_count: "
339        << m_store_count
340        << "]" << std::flush;
341}
342
343void
344Check::debugPrint()
345{
346    DPRINTF(RubyTest,
347        "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n",
348        m_address.getAddress(), (int)m_value,
349        TesterStatus_to_string(m_status).c_str(),
350        m_initiatingNode, m_store_count);
351}
352