1/*
2 * Copyright (c) 2012-2013, 2016-2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed here under.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Thomas Grass
38 *          Andreas Hansson
39 *          Sascha Bischoff
40 *          Neha Agarwal
41 */
42
43#include "cpu/testers/traffic_gen/dram_gen.hh"
44
45#include <algorithm>
46
47#include "base/random.hh"
48#include "base/trace.hh"
49#include "debug/TrafficGen.hh"
50
51
52DramGen::DramGen(SimObject &obj,
53                 MasterID master_id, Tick _duration,
54                 Addr start_addr, Addr end_addr,
55                 Addr _blocksize, Addr cacheline_size,
56                 Tick min_period, Tick max_period,
57                 uint8_t read_percent, Addr data_limit,
58                 unsigned int num_seq_pkts, unsigned int page_size,
59                 unsigned int nbr_of_banks_DRAM,
60                 unsigned int nbr_of_banks_util,
61                 unsigned int addr_mapping,
62                 unsigned int nbr_of_ranks)
63        : RandomGen(obj, master_id, _duration, start_addr, end_addr,
64          _blocksize, cacheline_size, min_period, max_period,
65          read_percent, data_limit),
66          numSeqPkts(num_seq_pkts), countNumSeqPkts(0), addr(0),
67          isRead(true), pageSize(page_size),
68          pageBits(floorLog2(page_size / _blocksize)),
69          bankBits(floorLog2(nbr_of_banks_DRAM)),
70          blockBits(floorLog2(_blocksize)),
71          nbrOfBanksDRAM(nbr_of_banks_DRAM),
72          nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping),
73          rankBits(floorLog2(nbr_of_ranks)),
74          nbrOfRanks(nbr_of_ranks)
75{
76    if (addrMapping != 1 && addrMapping != 0) {
77        addrMapping = 1;
78        warn("Unknown address mapping specified, using RoRaBaCoCh\n");
79    }
80
81    if (nbr_of_banks_util > nbr_of_banks_DRAM)
82        fatal("Attempting to use more banks (%d) than "
83              "what is available (%d)\n",
84              nbr_of_banks_util, nbr_of_banks_DRAM);
85}
86
87PacketPtr
88DramGen::getNextPacket()
89{
90    // if this is the first of the packets in series to be generated,
91    // start counting again
92    if (countNumSeqPkts == 0) {
93        countNumSeqPkts = numSeqPkts;
94
95        // choose if we generate a read or a write here
96        isRead = readPercent != 0 &&
97            (readPercent == 100 || random_mt.random(0, 100) < readPercent);
98
99        assert((readPercent == 0 && !isRead) ||
100               (readPercent == 100 && isRead) ||
101               readPercent != 100);
102
103        // pick a random bank
104        unsigned int new_bank =
105            random_mt.random<unsigned int>(0, nbrOfBanksUtil - 1);
106
107        // pick a random rank
108        unsigned int new_rank =
109            random_mt.random<unsigned int>(0, nbrOfRanks - 1);
110
111        // Generate the start address of the command series
112        // routine will update addr variable with bank, rank, and col
113        // bits updated for random traffic mode
114        genStartAddr(new_bank, new_rank);
115
116    } else {
117        // increment the column by one
118        if (addrMapping == 1)
119            // addrMapping=1: RoRaBaCoCh/RoRaBaChCo
120            // Simply increment addr by blocksize to increment
121            // the column by one
122            addr += blocksize;
123
124        else if (addrMapping == 0) {
125            // addrMapping=0: RoCoRaBaCh
126            // Explicity increment the column bits
127            unsigned int new_col = ((addr / blocksize /
128                                       nbrOfBanksDRAM / nbrOfRanks) %
129                                   (pageSize / blocksize)) + 1;
130            replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
131                        blockBits + bankBits + rankBits, new_col);
132        }
133    }
134
135    DPRINTF(TrafficGen, "DramGen::getNextPacket: %c to addr %x, "
136            "size %d, countNumSeqPkts: %d, numSeqPkts: %d\n",
137            isRead ? 'r' : 'w', addr, blocksize, countNumSeqPkts, numSeqPkts);
138
139    // create a new request packet
140    PacketPtr pkt = getPacket(addr, blocksize,
141                              isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
142
143    // add the amount of data manipulated to the total
144    dataManipulated += blocksize;
145
146    // subtract the number of packets remained to be generated
147    --countNumSeqPkts;
148
149    // return the generated packet
150    return pkt;
151}
152
153void
154DramGen::genStartAddr(unsigned int new_bank, unsigned int new_rank)
155{
156    // start by picking a random address in the range
157    addr = random_mt.random<Addr>(startAddr, endAddr - 1);
158
159    // round down to start address of a block, i.e. a DRAM burst
160    addr -= addr % blocksize;
161
162    // insert the bank bits at the right spot, and align the
163    // address to achieve the required hit length, this involves
164    // finding the appropriate start address such that all
165    // sequential packets target successive columns in the same
166    // page
167
168    // for example, if we have a stride size of 192B, which means
169    // for LPDDR3 where burstsize = 32B we have numSeqPkts = 6,
170    // the address generated previously can be such that these
171    // 192B cross the page boundary, hence it needs to be aligned
172    // so that they all belong to the same page for page hit
173    unsigned int columns_per_page = pageSize / blocksize;
174
175    // pick a random column, but ensure that there is room for
176    // numSeqPkts sequential columns in the same page
177    unsigned int new_col =
178        random_mt.random<unsigned int>(0, columns_per_page - numSeqPkts);
179
180    if (addrMapping == 1) {
181        // addrMapping=1: RoRaBaCoCh/RoRaBaChCo
182        // Block bits, then page bits, then bank bits, then rank bits
183        replaceBits(addr, blockBits + pageBits + bankBits - 1,
184                    blockBits + pageBits, new_bank);
185        replaceBits(addr, blockBits + pageBits - 1, blockBits, new_col);
186        if (rankBits != 0) {
187            replaceBits(addr, blockBits + pageBits + bankBits +rankBits - 1,
188                        blockBits + pageBits + bankBits, new_rank);
189        }
190    } else if (addrMapping == 0) {
191        // addrMapping=0: RoCoRaBaCh
192        // Block bits, then bank bits, then rank bits, then page bits
193        replaceBits(addr, blockBits + bankBits - 1, blockBits, new_bank);
194        replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
195                    blockBits + bankBits + rankBits, new_col);
196        if (rankBits != 0) {
197            replaceBits(addr, blockBits + bankBits + rankBits - 1,
198                        blockBits + bankBits, new_rank);
199        }
200    }
201}
202