gem5  v22.1.0.0
translation_gen.test.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2021 Google, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met: redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer;
8  * redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution;
11  * neither the name of the copyright holders nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30 
31 #include <initializer_list>
32 #include <list>
33 #include <memory>
34 #include <ostream>
35 #include <vector>
36 
37 #include "base/cprintf.hh"
38 #include "base/gtest/logging.hh"
39 #include "mem/translation_gen.hh"
40 
41 using testing::HasSubstr;
42 using testing::Pointwise;
43 using namespace gem5;
44 
45 namespace gem5
46 {
47 
48 // A dummy fault class so we have something to return from failed translations.
49 class FaultBase {};
50 
51 Fault dummyFault1 = std::make_shared<gem5::FaultBase>();
52 Fault dummyFault2 = std::make_shared<gem5::FaultBase>();
53 
54 std::ostream &
55 operator<<(std::ostream &os, const TranslationGen::Range &range)
56 {
57  if (range.fault == dummyFault1)
58  ccprintf(os, "%#x=>fault1", range.vaddr);
59  else if (range.fault == dummyFault2)
60  ccprintf(os, "%#x=>fault2", range.vaddr);
61  else
62  ccprintf(os, "%#x=>%#x [%#x]", range.vaddr, range.paddr, range.size);
63  return os;
64 }
65 
66 } // namespace gem5
67 
69 
70 // Compare ranges which are returned by the generator.
71 MATCHER(GenRangeEq, "")
72 {
73  const auto &[actual, expected] = arg;
74  // vaddr and fault should match no matter what.
75  if (actual.vaddr != expected.vaddr || actual.fault != expected.fault)
76  return false;
77  if (expected.fault) {
78  // If there was a fault, paddr and size don't matter.
79  return true;
80  } else {
81  // If there was no fault, check paddr and size.
82  return actual.paddr == expected.paddr && actual.size == expected.size;
83  }
84 }
85 
86 // Compare ranges which are sent to the translate function.
87 MATCHER(TransRangeEq, "")
88 {
89  const auto &[actual, expected] = arg;
90  // Only the vaddr and size fields are inputs to the translate function.
91  return actual.vaddr == expected.vaddr && actual.size == expected.size;
92 }
93 
95 {
96  public:
97  // Results to return from the translate function, one by one.
99  // All the Ranges which were passed into translate from the generator.
100  mutable RangeList args;
101 
102  private:
103  // Where we are in the results vector.
105 
106  public:
107  TestTranslationGen(Addr new_start, Addr new_size,
108  std::initializer_list<Range> ranges={}) :
109  TranslationGen(new_start, new_size), results(ranges),
110  resultPos(results.begin())
111  {}
112 
113  void
114  translate(Range &range) const override
115  {
116  // First, record what range we were asked to translate.
117  args.emplace_back(range);
118  // Then, if we're not out of results to return...
119  if (resultPos != results.end()) {
120  // Record the fault we're supposed to return, if any.
121  range.fault = resultPos->fault;
122  if (!range.fault) {
123  // If there wasn't a fault, size and paddr are meaningful.
124  range.size = resultPos->size;
125  range.paddr = resultPos->paddr;
126  }
127  // Advance to the next result.
128  resultPos++;
129  }
130  }
131 };
132 
133 TEST(TranslationGen, Accessors)
134 {
135  TestTranslationGen gen1(0x10000, 0x20000);
136 
137  EXPECT_EQ(gen1.start(), 0x10000);
138  EXPECT_EQ(gen1.size(), 0x20000);
139 
140  TestTranslationGen gen2(0x3456, 0x6543);
141 
142  EXPECT_EQ(gen2.start(), 0x3456);
143  EXPECT_EQ(gen2.size(), 0x6543);
144 }
145 
146 TEST(TranslationGen, BeginAndEnd)
147 {
148  TestTranslationGen gen1(0x10000, 0x20000);
149 
150  EXPECT_NE(gen1.begin(), gen1.end());
151  EXPECT_EQ(gen1.begin(), gen1.begin());
152  EXPECT_EQ(gen1.end(), gen1.end());
153 
154  TestTranslationGen gen2(0x30000, 0x40000);
155 
156  EXPECT_NE(gen1.begin(), gen2.begin());
157  EXPECT_EQ(gen1.end(), gen2.end());
158 }
159 
160 TEST(TranslationGen, SuccessfulTwoStep)
161 {
162  TestTranslationGen gen(0x10000, 0x10000, {
163  // Results for translate.
164  {0x0, 0x8000, 0x30000, NoFault},
165  {0x0, 0x8000, 0x40000, NoFault}
166  });
167 
168  RangeList range_list;
169  for (const auto &range: gen)
170  range_list.emplace_back(range);
171 
172  // What the generator should return.
173  const RangeList expected_gen{
174  {0x10000, 0x8000, 0x30000, NoFault},
175  {0x18000, 0x8000, 0x40000, NoFault}
176  };
177  EXPECT_THAT(range_list, Pointwise(GenRangeEq(), expected_gen));
178 
179  // What the generator should have been asked to translate.
180  const RangeList expected_trans{
181  {0x10000, 0x10000, 0x0, NoFault},
182  {0x18000, 0x8000, 0x0, NoFault}
183  };
184  EXPECT_THAT(gen.args, Pointwise(TransRangeEq(), expected_trans));
185 }
186 
187 TEST(TranslationGen, RetryOnFault)
188 {
189  TestTranslationGen gen(0x10000, 0x10000, {
190  // Results for translate.
191  {0x0, 0x8000, 0x30000, NoFault},
192  {0x0, 0x0, 0x0, dummyFault1},
193  {0x0, 0x8000, 0x40000, NoFault}
194  });
195 
196  RangeList range_list;
197  for (const auto &range: gen)
198  range_list.emplace_back(range);
199 
200  // What the generator should return.
201  const RangeList expected_gen{
202  {0x10000, 0x8000, 0x30000, NoFault},
203  {0x18000, 0x0, 0x0, dummyFault1},
204  {0x18000, 0x8000, 0x40000, NoFault}
205  };
206  EXPECT_THAT(range_list, Pointwise(GenRangeEq(), expected_gen));
207 
208  // What the generator should have been asked to translate.
209  const RangeList expected_trans{
210  {0x10000, 0x10000, 0x0, NoFault},
211  {0x18000, 0x8000, 0x0, NoFault},
212  {0x18000, 0x8000, 0x0, NoFault}
213  };
214  EXPECT_THAT(gen.args, Pointwise(TransRangeEq(), expected_trans));
215 }
216 
217 TEST(TranslationGen, RetryTwiceOnFault)
218 {
219  TestTranslationGen gen(0x10000, 0x10000, {
220  // Results for translate.
221  {0x0, 0x8000, 0x30000, NoFault},
222  {0x0, 0x0, 0x0, dummyFault1},
223  {0x0, 0x0, 0x0, dummyFault2},
224  {0x0, 0x8000, 0x40000, NoFault}
225  });
226 
227  RangeList range_list;
228  for (const auto &range: gen)
229  range_list.emplace_back(range);
230 
231  // What the generator should return.
232  const RangeList expected_gen{
233  {0x10000, 0x8000, 0x30000, NoFault},
234  {0x18000, 0x0, 0x0, dummyFault1},
235  {0x18000, 0x0, 0x0, dummyFault2},
236  {0x18000, 0x8000, 0x40000, NoFault}
237  };
238  EXPECT_THAT(range_list, Pointwise(GenRangeEq(), expected_gen));
239 
240  // What the generator should have been asked to translate.
241  const RangeList expected_trans{
242  {0x10000, 0x10000, 0x0, NoFault},
243  {0x18000, 0x8000, 0x0, NoFault},
244  {0x18000, 0x8000, 0x0, NoFault},
245  {0x18000, 0x8000, 0x0, NoFault}
246  };
247  EXPECT_THAT(gen.args, Pointwise(TransRangeEq(), expected_trans));
248 }
249 
250 TEST(TranslationGen, FaultAtStart)
251 {
252  TestTranslationGen gen(0x10000, 0x10000, {
253  // Results for translate.
254  {0x0, 0x0, 0x0, dummyFault1},
255  {0x0, 0x8000, 0x30000, NoFault},
256  {0x0, 0x8000, 0x40000, NoFault}
257  });
258 
259  RangeList range_list;
260  for (const auto &range: gen)
261  range_list.emplace_back(range);
262 
263  // What the generator should return.
264  const RangeList expected_gen{
265  {0x10000, 0x0, 0x0, dummyFault1},
266  {0x10000, 0x8000, 0x30000, NoFault},
267  {0x18000, 0x8000, 0x40000, NoFault}
268  };
269  EXPECT_THAT(range_list, Pointwise(GenRangeEq(), expected_gen));
270 
271  // What the generator should have been asked to translate.
272  const RangeList expected_trans{
273  {0x10000, 0x10000, 0x0, NoFault},
274  {0x10000, 0x10000, 0x0, NoFault},
275  {0x18000, 0x8000, 0x0, NoFault}
276  };
277  EXPECT_THAT(gen.args, Pointwise(TransRangeEq(), expected_trans));
278 }
279 
280 TEST(TranslationGen, FaultInMiddle)
281 {
282  TestTranslationGen gen(0x10000, 0x18000, {
283  // Results for translate.
284  {0x0, 0x8000, 0x30000, NoFault},
285  {0x0, 0x0, 0x0, dummyFault1},
286  {0x0, 0x8000, 0x40000, NoFault},
287  {0x0, 0x8000, 0x50000, NoFault}
288  });
289 
290  RangeList range_list;
291  for (const auto &range: gen)
292  range_list.emplace_back(range);
293 
294  // What the generator should return.
295  const RangeList expected_gen{
296  {0x10000, 0x8000, 0x30000, NoFault},
297  {0x18000, 0x0, 0x0, dummyFault1},
298  {0x18000, 0x8000, 0x40000, NoFault},
299  {0x20000, 0x8000, 0x50000, NoFault}
300  };
301  EXPECT_THAT(range_list, Pointwise(GenRangeEq(), expected_gen));
302 
303  // What the generator should have been asked to translate.
304  const RangeList expected_trans{
305  {0x10000, 0x18000, 0x0, NoFault},
306  {0x18000, 0x10000, 0x0, NoFault},
307  {0x18000, 0x10000, 0x0, NoFault},
308  {0x20000, 0x8000, 0x0, NoFault}
309  };
310  EXPECT_THAT(gen.args, Pointwise(TransRangeEq(), expected_trans));
311 }
312 
313 TEST(TranslationGen, VariablePageSize)
314 {
315  TestTranslationGen gen(0x10000, 0x20000, {
316  // Results for translate.
317  {0x0, 0x8000, 0x30000, NoFault},
318  {0x0, 0x10000, 0x40000, NoFault},
319  {0x0, 0x8000, 0x50000, NoFault}
320  });
321 
322  RangeList range_list;
323  for (const auto &range: gen)
324  range_list.emplace_back(range);
325 
326  // What the generator should return.
327  const RangeList expected_gen{
328  {0x10000, 0x8000, 0x30000, NoFault},
329  {0x18000, 0x10000, 0x40000, NoFault},
330  {0x28000, 0x8000, 0x50000, NoFault}
331  };
332  EXPECT_THAT(range_list, Pointwise(GenRangeEq(), expected_gen));
333 
334  // What the generator should have been asked to translate.
335  const RangeList expected_trans{
336  {0x10000, 0x20000, 0x0, NoFault},
337  {0x18000, 0x18000, 0x0, NoFault},
338  {0x28000, 0x8000, 0x0, NoFault}
339  };
340  EXPECT_THAT(gen.args, Pointwise(TransRangeEq(), expected_trans));
341 }
342 
343 TEST(TranslationGenDeathTest, IncrementEndIterator)
344 {
345  TestTranslationGen gen(0x10000, 0x20000);
346  gtestLogOutput.str("");
347  ASSERT_ANY_THROW(gen.end()++);
348  EXPECT_THAT(gtestLogOutput.str(),
349  HasSubstr("Can't increment end iterator."));
350 }
const std::vector< Range > results
TestTranslationGen(Addr new_start, Addr new_size, std::initializer_list< Range > ranges={})
void translate(Range &range) const override
Subclasses implement this function to complete TranslationGen.
std::vector< Range >::const_iterator resultPos
TranslationGen is a base class for a generator object which returns information about address transla...
const_iterator begin() const
const_iterator end() const
std::vector< SwitchingFiber * > expected({ &a, &b, &a, &a, &a, &b, &c, &a, &c, &c, &c })
Bitfield< 17 > os
Definition: misc.hh:810
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::shared_ptr< FaultBase > Fault
Definition: types.hh:248
Fault dummyFault2
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
std::ostream & operator<<(std::ostream &os, const ArmSemihosting::InPlaceArg &ipa)
Fault dummyFault1
thread_local GTestLogOutput gtestLogOutput
Definition: logging.cc:33
constexpr decltype(nullptr) NoFault
Definition: types.hh:253
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
This structure represents a single, contiguous translation, or carries information about whatever fau...
TEST(TranslationGen, Accessors)
MATCHER(GenRangeEq, "")

Generated on Wed Dec 21 2022 10:22:39 for gem5 by doxygen 1.9.1