Check.cc revision 7053
110107Sradhika.jagtap@ARM.com/*
210107Sradhika.jagtap@ARM.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
310107Sradhika.jagtap@ARM.com * Copyright (c) 2009 Advanced Micro Devices, Inc.
410107Sradhika.jagtap@ARM.com * All rights reserved.
510107Sradhika.jagtap@ARM.com *
610107Sradhika.jagtap@ARM.com * Redistribution and use in source and binary forms, with or without
710107Sradhika.jagtap@ARM.com * modification, are permitted provided that the following conditions are
810107Sradhika.jagtap@ARM.com * met: redistributions of source code must retain the above copyright
910107Sradhika.jagtap@ARM.com * notice, this list of conditions and the following disclaimer;
1010107Sradhika.jagtap@ARM.com * redistributions in binary form must reproduce the above copyright
1110107Sradhika.jagtap@ARM.com * notice, this list of conditions and the following disclaimer in the
1210107Sradhika.jagtap@ARM.com * documentation and/or other materials provided with the distribution;
1310107Sradhika.jagtap@ARM.com * neither the name of the copyright holders nor the names of its
1410107Sradhika.jagtap@ARM.com * contributors may be used to endorse or promote products derived from
1510107Sradhika.jagtap@ARM.com * this software without specific prior written permission.
1610107Sradhika.jagtap@ARM.com *
1710107Sradhika.jagtap@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1810107Sradhika.jagtap@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1910107Sradhika.jagtap@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2010107Sradhika.jagtap@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2110107Sradhika.jagtap@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2210107Sradhika.jagtap@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2310107Sradhika.jagtap@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2410107Sradhika.jagtap@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2510107Sradhika.jagtap@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2610107Sradhika.jagtap@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2710107Sradhika.jagtap@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2810107Sradhika.jagtap@ARM.com */
2910107Sradhika.jagtap@ARM.com
3010107Sradhika.jagtap@ARM.com#include "cpu/rubytest/Check.hh"
3110107Sradhika.jagtap@ARM.com#include "mem/ruby/common/SubBlock.hh"
3210107Sradhika.jagtap@ARM.com#include "mem/ruby/system/Sequencer.hh"
3310107Sradhika.jagtap@ARM.com#include "mem/ruby/system/System.hh"
3410107Sradhika.jagtap@ARM.com
3510107Sradhika.jagtap@ARM.comtypedef RubyTester::SenderState SenderState;
3610107Sradhika.jagtap@ARM.com
3710107Sradhika.jagtap@ARM.comCheck::Check(const Address& address, const Address& pc,
3810107Sradhika.jagtap@ARM.com             int _num_cpu_sequencers, RubyTester* _tester)
3910107Sradhika.jagtap@ARM.com    : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
4010107Sradhika.jagtap@ARM.com{
4110107Sradhika.jagtap@ARM.com    m_status = TesterStatus_Idle;
4210107Sradhika.jagtap@ARM.com
4310107Sradhika.jagtap@ARM.com    pickValue();
4410107Sradhika.jagtap@ARM.com    pickInitiatingNode();
4510107Sradhika.jagtap@ARM.com    changeAddress(address);
4610107Sradhika.jagtap@ARM.com    m_pc = pc;
4710107Sradhika.jagtap@ARM.com    m_access_mode = AccessModeType(random() % AccessModeType_NUM);
4810107Sradhika.jagtap@ARM.com    m_store_count = 0;
4910107Sradhika.jagtap@ARM.com}
5010107Sradhika.jagtap@ARM.com
5110107Sradhika.jagtap@ARM.comvoid
5210107Sradhika.jagtap@ARM.comCheck::initiate()
5310107Sradhika.jagtap@ARM.com{
5410107Sradhika.jagtap@ARM.com    DPRINTF(RubyTest, "initiating\n");
5510107Sradhika.jagtap@ARM.com    debugPrint();
5610107Sradhika.jagtap@ARM.com
5710107Sradhika.jagtap@ARM.com    // currently no protocols support prefetches
5810107Sradhika.jagtap@ARM.com    if (false && (random() & 0xf) == 0) {
5910107Sradhika.jagtap@ARM.com        initiatePrefetch(); // Prefetch from random processor
6010107Sradhika.jagtap@ARM.com    }
6110107Sradhika.jagtap@ARM.com
6210107Sradhika.jagtap@ARM.com    if (m_status == TesterStatus_Idle) {
6310107Sradhika.jagtap@ARM.com        initiateAction();
6410107Sradhika.jagtap@ARM.com    } else if (m_status == TesterStatus_Ready) {
6510107Sradhika.jagtap@ARM.com        initiateCheck();
6610107Sradhika.jagtap@ARM.com    } else {
6710107Sradhika.jagtap@ARM.com        // Pending - do nothing
6810107Sradhika.jagtap@ARM.com        DPRINTF(RubyTest,
6910107Sradhika.jagtap@ARM.com                "initiating action/check - failed: action/check is pending\n");
7010107Sradhika.jagtap@ARM.com    }
7110107Sradhika.jagtap@ARM.com}
7210107Sradhika.jagtap@ARM.com
7310107Sradhika.jagtap@ARM.comvoid
7410269Sradhika.jagtap@ARM.comCheck::initiatePrefetch()
7510107Sradhika.jagtap@ARM.com{
7610107Sradhika.jagtap@ARM.com    DPRINTF(RubyTest, "initiating prefetch\n");
7710269Sradhika.jagtap@ARM.com
7810269Sradhika.jagtap@ARM.com    int index = random() % m_num_cpu_sequencers;
7910269Sradhika.jagtap@ARM.com    RubyTester::CpuPort* port =
8010269Sradhika.jagtap@ARM.com        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
8110269Sradhika.jagtap@ARM.com
8210269Sradhika.jagtap@ARM.com    Request::Flags flags;
8310269Sradhika.jagtap@ARM.com    flags.set(Request::PREFETCH);
8410269Sradhika.jagtap@ARM.com
8510269Sradhika.jagtap@ARM.com    // Prefetches are assumed to be 0 sized
8610269Sradhika.jagtap@ARM.com    Request *req = new Request(m_address.getAddress(), 0, flags, curTick,
8710269Sradhika.jagtap@ARM.com                               m_pc.getAddress());
8810269Sradhika.jagtap@ARM.com
8910269Sradhika.jagtap@ARM.com    Packet::Command cmd;
9010269Sradhika.jagtap@ARM.com
9110269Sradhika.jagtap@ARM.com    // 1 in 8 chance this will be an exclusive prefetch
9210269Sradhika.jagtap@ARM.com    if ((random() & 0x7) != 0) {
9310269Sradhika.jagtap@ARM.com        cmd = MemCmd::ReadReq;
9410269Sradhika.jagtap@ARM.com
9510269Sradhika.jagtap@ARM.com        // 50% chance that the request will be an instruction fetch
9610269Sradhika.jagtap@ARM.com        if ((random() & 0x1) == 0) {
9710269Sradhika.jagtap@ARM.com            flags.set(Request::INST_FETCH);
9810269Sradhika.jagtap@ARM.com        }
9910269Sradhika.jagtap@ARM.com    } else {
10010269Sradhika.jagtap@ARM.com        cmd = MemCmd::WriteReq;
10110107Sradhika.jagtap@ARM.com        flags.set(Request::PF_EXCLUSIVE);
10210107Sradhika.jagtap@ARM.com    }
10310107Sradhika.jagtap@ARM.com
10410107Sradhika.jagtap@ARM.com    PacketPtr pkt = new Packet(req, cmd, port->idx);
10510107Sradhika.jagtap@ARM.com
10610107Sradhika.jagtap@ARM.com    // push the subblock onto the sender state.  The sequencer will
10710107Sradhika.jagtap@ARM.com    // update the subblock on the return
10810107Sradhika.jagtap@ARM.com    pkt->senderState =
10910107Sradhika.jagtap@ARM.com        new SenderState(m_address, req->getSize(), pkt->senderState);
11010107Sradhika.jagtap@ARM.com
11110107Sradhika.jagtap@ARM.com    if (port->sendTiming(pkt)) {
11210107Sradhika.jagtap@ARM.com        DPRINTF(RubyTest, "successfully initiated prefetch.\n");
11310107Sradhika.jagtap@ARM.com    } else {
11410107Sradhika.jagtap@ARM.com        // If the packet did not issue, must delete
11510107Sradhika.jagtap@ARM.com        SenderState* senderState =  safe_cast<SenderState*>(pkt->senderState);
11610107Sradhika.jagtap@ARM.com        pkt->senderState = senderState->saved;
11710107Sradhika.jagtap@ARM.com        delete senderState;
11810107Sradhika.jagtap@ARM.com        delete pkt->req;
11910107Sradhika.jagtap@ARM.com        delete pkt;
12010107Sradhika.jagtap@ARM.com
12110107Sradhika.jagtap@ARM.com        DPRINTF(RubyTest,
12210107Sradhika.jagtap@ARM.com                "prefetch initiation failed because Port was busy.\n");
12310107Sradhika.jagtap@ARM.com    }
12410107Sradhika.jagtap@ARM.com}
12510107Sradhika.jagtap@ARM.com
12610107Sradhika.jagtap@ARM.comvoid
12710107Sradhika.jagtap@ARM.comCheck::initiateAction()
12810107Sradhika.jagtap@ARM.com{
12910107Sradhika.jagtap@ARM.com    DPRINTF(RubyTest, "initiating Action\n");
13010107Sradhika.jagtap@ARM.com    assert(m_status == TesterStatus_Idle);
13110107Sradhika.jagtap@ARM.com
13210107Sradhika.jagtap@ARM.com    int index = random() % m_num_cpu_sequencers;
13310107Sradhika.jagtap@ARM.com    RubyTester::CpuPort* port =
13410107Sradhika.jagtap@ARM.com        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
13510107Sradhika.jagtap@ARM.com
13610107Sradhika.jagtap@ARM.com    Request::Flags flags;
13710107Sradhika.jagtap@ARM.com
13810107Sradhika.jagtap@ARM.com    // Create the particular address for the next byte to be written
13910107Sradhika.jagtap@ARM.com    Address writeAddr(m_address.getAddress() + m_store_count);
14010107Sradhika.jagtap@ARM.com
14110107Sradhika.jagtap@ARM.com    // Stores are assumed to be 1 byte-sized
14210107Sradhika.jagtap@ARM.com    Request *req = new Request(writeAddr.getAddress(), 1, flags, curTick,
14310107Sradhika.jagtap@ARM.com                               m_pc.getAddress());
14410107Sradhika.jagtap@ARM.com
14510107Sradhika.jagtap@ARM.com    Packet::Command cmd;
14610107Sradhika.jagtap@ARM.com
14710107Sradhika.jagtap@ARM.com    // 1 out of 8 chance, issue an atomic rather than a write
14810107Sradhika.jagtap@ARM.com    // if ((random() & 0x7) == 0) {
14910107Sradhika.jagtap@ARM.com    //     cmd = MemCmd::SwapReq;
15010107Sradhika.jagtap@ARM.com    // } else {
15110107Sradhika.jagtap@ARM.com    cmd = MemCmd::WriteReq;
15210107Sradhika.jagtap@ARM.com    // }
15310107Sradhika.jagtap@ARM.com
15410107Sradhika.jagtap@ARM.com    PacketPtr pkt = new Packet(req, cmd, port->idx);
15510107Sradhika.jagtap@ARM.com    uint8_t* writeData = new uint8_t;
15610107Sradhika.jagtap@ARM.com    *writeData = m_value + m_store_count;
15710107Sradhika.jagtap@ARM.com    pkt->dataDynamic(writeData);
15810107Sradhika.jagtap@ARM.com
15910107Sradhika.jagtap@ARM.com    DPRINTF(RubyTest, "data 0x%x check 0x%x\n",
16010107Sradhika.jagtap@ARM.com            *(pkt->getPtr<uint8_t>()), *writeData);
16110107Sradhika.jagtap@ARM.com
16210107Sradhika.jagtap@ARM.com    // push the subblock onto the sender state.  The sequencer will
16310107Sradhika.jagtap@ARM.com    // update the subblock on the return
16410107Sradhika.jagtap@ARM.com    pkt->senderState =
16510107Sradhika.jagtap@ARM.com        new SenderState(writeAddr, req->getSize(), pkt->senderState);
16610107Sradhika.jagtap@ARM.com
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    // Checks are sized depending on the number of bytes written
202    Request *req = new Request(m_address.getAddress(), CHECK_SIZE, flags,
203                               curTick, m_pc.getAddress());
204
205    // 50% chance that the request will be an instruction fetch
206    if ((random() & 0x1) == 0) {
207        flags.set(Request::INST_FETCH);
208    }
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                WARN_EXPR(proc);
274                WARN_EXPR(address);
275                WARN_EXPR(data);
276                WARN_EXPR(byte_number);
277                WARN_EXPR((int)m_value + byte_number);
278                WARN_EXPR((int)data->getByte(byte_number));
279                WARN_EXPR(*this);
280                WARN_EXPR(g_eventQueue_ptr->getTime());
281                ERROR_MSG("Action/check failure");
282            }
283        }
284        DPRINTF(RubyTest, "Action/check success\n");
285        debugPrint();
286
287        // successful check complete, increment complete
288        m_tester_ptr->incrementCheckCompletions();
289
290        m_status = TesterStatus_Idle;
291        pickValue();
292
293    } else {
294        WARN_EXPR(*this);
295        WARN_EXPR(proc);
296        WARN_EXPR(data);
297        WARN_EXPR(m_status);
298        WARN_EXPR(g_eventQueue_ptr->getTime());
299        ERROR_MSG("Unexpected TesterStatus");
300    }
301
302    DPRINTF(RubyTest, "proc: %d, Address: 0x%x\n", proc,
303            getAddress().getLineAddress());
304    DPRINTF(RubyTest, "Callback done\n");
305    debugPrint();
306}
307
308void
309Check::changeAddress(const Address& address)
310{
311    assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready);
312    m_status = TesterStatus_Idle;
313    m_address = address;
314    m_store_count = 0;
315}
316
317void
318Check::pickValue()
319{
320    assert(m_status == TesterStatus_Idle);
321    m_status = TesterStatus_Idle;
322    m_value = random() & 0xff; // One byte
323    m_store_count = 0;
324}
325
326void
327Check::pickInitiatingNode()
328{
329    assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready);
330    m_status = TesterStatus_Idle;
331    m_initiatingNode = (random() % m_num_cpu_sequencers);
332    DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
333    m_store_count = 0;
334}
335
336void
337Check::print(ostream& out) const
338{
339    out << "["
340        << m_address << ", value: "
341        << (int)m_value << ", status: "
342        << m_status << ", initiating node: "
343        << m_initiatingNode << ", store_count: "
344        << m_store_count
345        << "]" << flush;
346}
347
348void
349Check::debugPrint()
350{
351    DPRINTF(RubyTest,
352        "[%#x, value: %d, status: %s, initiating node: %d, store_count: %d]\n",
353        m_address.getAddress(), (int)m_value,
354        TesterStatus_to_string(m_status).c_str(),
355        m_initiatingNode, m_store_count);
356}
357