Check.cc revision 7568
17584SAli.Saidi@arm.com/*
27584SAli.Saidi@arm.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
37584SAli.Saidi@arm.com * Copyright (c) 2009 Advanced Micro Devices, Inc.
47584SAli.Saidi@arm.com * All rights reserved.
57584SAli.Saidi@arm.com *
67584SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without
77584SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are
87584SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright
97584SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer;
107584SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright
117584SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the
127584SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution;
137584SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its
147584SAli.Saidi@arm.com * contributors may be used to endorse or promote products derived from
157584SAli.Saidi@arm.com * this software without specific prior written permission.
167584SAli.Saidi@arm.com *
177584SAli.Saidi@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
187584SAli.Saidi@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
197584SAli.Saidi@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
207584SAli.Saidi@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
217584SAli.Saidi@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
227584SAli.Saidi@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
237584SAli.Saidi@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
247584SAli.Saidi@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
257584SAli.Saidi@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
267584SAli.Saidi@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
277584SAli.Saidi@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
287584SAli.Saidi@arm.com */
297584SAli.Saidi@arm.com
307584SAli.Saidi@arm.com#include "cpu/rubytest/Check.hh"
317584SAli.Saidi@arm.com#include "mem/ruby/common/SubBlock.hh"
327584SAli.Saidi@arm.com#include "mem/ruby/system/Sequencer.hh"
337584SAli.Saidi@arm.com#include "mem/ruby/system/System.hh"
347584SAli.Saidi@arm.com
357584SAli.Saidi@arm.comtypedef RubyTester::SenderState SenderState;
367584SAli.Saidi@arm.com
377584SAli.Saidi@arm.comCheck::Check(const Address& address, const Address& pc,
387584SAli.Saidi@arm.com             int _num_cpu_sequencers, RubyTester* _tester)
397584SAli.Saidi@arm.com    : m_num_cpu_sequencers(_num_cpu_sequencers), m_tester_ptr(_tester)
407584SAli.Saidi@arm.com{
417584SAli.Saidi@arm.com    m_status = TesterStatus_Idle;
427584SAli.Saidi@arm.com
437584SAli.Saidi@arm.com    pickValue();
447584SAli.Saidi@arm.com    pickInitiatingNode();
457584SAli.Saidi@arm.com    changeAddress(address);
467584SAli.Saidi@arm.com    m_pc = pc;
477584SAli.Saidi@arm.com    m_access_mode = AccessModeType(random() % AccessModeType_NUM);
487584SAli.Saidi@arm.com    m_store_count = 0;
497584SAli.Saidi@arm.com}
507584SAli.Saidi@arm.com
517584SAli.Saidi@arm.comvoid
527584SAli.Saidi@arm.comCheck::initiate()
537584SAli.Saidi@arm.com{
547584SAli.Saidi@arm.com    DPRINTF(RubyTest, "initiating\n");
557584SAli.Saidi@arm.com    debugPrint();
567584SAli.Saidi@arm.com
577584SAli.Saidi@arm.com    // currently no protocols support prefetches
587584SAli.Saidi@arm.com    if (false && (random() & 0xf) == 0) {
597584SAli.Saidi@arm.com        initiatePrefetch(); // Prefetch from random processor
607584SAli.Saidi@arm.com    }
617587SAli.Saidi@arm.com
627584SAli.Saidi@arm.com    if (m_status == TesterStatus_Idle) {
637584SAli.Saidi@arm.com        initiateAction();
647584SAli.Saidi@arm.com    } else if (m_status == TesterStatus_Ready) {
657584SAli.Saidi@arm.com        initiateCheck();
667584SAli.Saidi@arm.com    } else {
677584SAli.Saidi@arm.com        // Pending - do nothing
687584SAli.Saidi@arm.com        DPRINTF(RubyTest,
697584SAli.Saidi@arm.com                "initiating action/check - failed: action/check is pending\n");
707584SAli.Saidi@arm.com    }
717584SAli.Saidi@arm.com}
727584SAli.Saidi@arm.com
737584SAli.Saidi@arm.comvoid
747584SAli.Saidi@arm.comCheck::initiatePrefetch()
757584SAli.Saidi@arm.com{
767584SAli.Saidi@arm.com    DPRINTF(RubyTest, "initiating prefetch\n");
777584SAli.Saidi@arm.com
787584SAli.Saidi@arm.com    int index = random() % m_num_cpu_sequencers;
797584SAli.Saidi@arm.com    RubyTester::CpuPort* port =
807584SAli.Saidi@arm.com        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
817584SAli.Saidi@arm.com
827584SAli.Saidi@arm.com    Request::Flags flags;
837584SAli.Saidi@arm.com    flags.set(Request::PREFETCH);
847584SAli.Saidi@arm.com
857584SAli.Saidi@arm.com    Packet::Command cmd;
867584SAli.Saidi@arm.com
877584SAli.Saidi@arm.com    // 1 in 8 chance this will be an exclusive prefetch
887584SAli.Saidi@arm.com    if ((random() & 0x7) != 0) {
897584SAli.Saidi@arm.com        cmd = MemCmd::ReadReq;
907584SAli.Saidi@arm.com
917584SAli.Saidi@arm.com        // 50% chance that the request will be an instruction fetch
927584SAli.Saidi@arm.com        if ((random() & 0x1) == 0) {
937584SAli.Saidi@arm.com            flags.set(Request::INST_FETCH);
947584SAli.Saidi@arm.com        }
957584SAli.Saidi@arm.com    } else {
967584SAli.Saidi@arm.com        cmd = MemCmd::WriteReq;
977584SAli.Saidi@arm.com        flags.set(Request::PF_EXCLUSIVE);
987584SAli.Saidi@arm.com    }
997584SAli.Saidi@arm.com
1007584SAli.Saidi@arm.com    // Prefetches are assumed to be 0 sized
1017584SAli.Saidi@arm.com    Request *req = new Request(m_address.getAddress(), 0, flags, curTick,
1027584SAli.Saidi@arm.com                               m_pc.getAddress());
1037584SAli.Saidi@arm.com
1047584SAli.Saidi@arm.com    PacketPtr pkt = new Packet(req, cmd, port->idx);
1057584SAli.Saidi@arm.com
1067584SAli.Saidi@arm.com    // push the subblock onto the sender state.  The sequencer will
1077584SAli.Saidi@arm.com    // update the subblock on the return
1087584SAli.Saidi@arm.com    pkt->senderState =
1097584SAli.Saidi@arm.com        new SenderState(m_address, req->getSize(), pkt->senderState);
1107584SAli.Saidi@arm.com
1117584SAli.Saidi@arm.com    if (port->sendTiming(pkt)) {
1127584SAli.Saidi@arm.com        DPRINTF(RubyTest, "successfully initiated prefetch.\n");
1137584SAli.Saidi@arm.com    } else {
1147584SAli.Saidi@arm.com        // If the packet did not issue, must delete
1157584SAli.Saidi@arm.com        SenderState* senderState =  safe_cast<SenderState*>(pkt->senderState);
1167584SAli.Saidi@arm.com        pkt->senderState = senderState->saved;
1177584SAli.Saidi@arm.com        delete senderState;
1187584SAli.Saidi@arm.com        delete pkt->req;
1197584SAli.Saidi@arm.com        delete pkt;
1207584SAli.Saidi@arm.com
1217584SAli.Saidi@arm.com        DPRINTF(RubyTest,
1227584SAli.Saidi@arm.com                "prefetch initiation failed because Port was busy.\n");
1237584SAli.Saidi@arm.com    }
1247584SAli.Saidi@arm.com}
1257584SAli.Saidi@arm.com
1267584SAli.Saidi@arm.comvoid
1277584SAli.Saidi@arm.comCheck::initiateAction()
1287584SAli.Saidi@arm.com{
1297584SAli.Saidi@arm.com    DPRINTF(RubyTest, "initiating Action\n");
1307584SAli.Saidi@arm.com    assert(m_status == TesterStatus_Idle);
1317584SAli.Saidi@arm.com
1327584SAli.Saidi@arm.com    int index = random() % m_num_cpu_sequencers;
1337584SAli.Saidi@arm.com    RubyTester::CpuPort* port =
1347584SAli.Saidi@arm.com        safe_cast<RubyTester::CpuPort*>(m_tester_ptr->getCpuPort(index));
1357584SAli.Saidi@arm.com
1367584SAli.Saidi@arm.com    Request::Flags flags;
1377584SAli.Saidi@arm.com
1387584SAli.Saidi@arm.com    // Create the particular address for the next byte to be written
1397584SAli.Saidi@arm.com    Address writeAddr(m_address.getAddress() + m_store_count);
1407584SAli.Saidi@arm.com
1417584SAli.Saidi@arm.com    // Stores are assumed to be 1 byte-sized
1427584SAli.Saidi@arm.com    Request *req = new Request(writeAddr.getAddress(), 1, flags, curTick,
1437584SAli.Saidi@arm.com                               m_pc.getAddress());
1447584SAli.Saidi@arm.com
1457584SAli.Saidi@arm.com    Packet::Command cmd;
1467584SAli.Saidi@arm.com
1477584SAli.Saidi@arm.com    // 1 out of 8 chance, issue an atomic rather than a write
1487584SAli.Saidi@arm.com    // if ((random() & 0x7) == 0) {
1497584SAli.Saidi@arm.com    //     cmd = MemCmd::SwapReq;
1507584SAli.Saidi@arm.com    // } else {
1517584SAli.Saidi@arm.com    cmd = MemCmd::WriteReq;
1527584SAli.Saidi@arm.com    // }
1537584SAli.Saidi@arm.com
1547584SAli.Saidi@arm.com    PacketPtr pkt = new Packet(req, cmd, port->idx);
1557584SAli.Saidi@arm.com    uint8_t* writeData = new uint8_t;
1567584SAli.Saidi@arm.com    *writeData = m_value + m_store_count;
1577584SAli.Saidi@arm.com    pkt->dataDynamic(writeData);
1587584SAli.Saidi@arm.com
1597584SAli.Saidi@arm.com    DPRINTF(RubyTest, "data 0x%x check 0x%x\n",
1607584SAli.Saidi@arm.com            *(pkt->getPtr<uint8_t>()), *writeData);
1617584SAli.Saidi@arm.com
1627584SAli.Saidi@arm.com    // push the subblock onto the sender state.  The sequencer will
1637584SAli.Saidi@arm.com    // update the subblock on the return
1647584SAli.Saidi@arm.com    pkt->senderState =
1657584SAli.Saidi@arm.com        new SenderState(writeAddr, req->getSize(), pkt->senderState);
1667584SAli.Saidi@arm.com
1677584SAli.Saidi@arm.com    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                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(std::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        << "]" << std::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