OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [tests/] [rtl/] [TestDivider.cpp] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
// Copyright Jamie Iles, 2017
2
//
3
// This file is part of s80x86.
4
//
5
// s80x86 is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
//
10
// s80x86 is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with s80x86.  If not, see <http://www.gnu.org/licenses/>.
17
 
18
#include <stdexcept>
19
#include <VDivider.h>
20
#include "VerilogTestbench.h"
21
 
22
using DivideError = std::runtime_error;
23
 
24
class DividerTestbench : public VerilogTestbench<VDivider>,
25
                         public ::testing::Test
26
{
27
public:
28
    DividerTestbench() : done(false), quotient(0), remainder(0)
29
    {
30
        reset();
31
 
32
        periodic(ClockCapture, [this] {
33
            if (this->dut.complete) {
34
                this->done = true;
35
                this->quotient = this->dut.quotient;
36
                this->remainder = this->dut.remainder;
37
            }
38
        });
39
    }
40
    void divide(uint32_t dividend,
41
                uint16_t divisor,
42
                bool is_8_bit = false,
43
                bool is_signed = false);
44
 
45
protected:
46
    bool done;
47
    uint16_t quotient, remainder;
48
};
49
 
50
void DividerTestbench::divide(uint32_t dividend,
51
                              uint16_t divisor,
52
                              bool is_8_bit,
53
                              bool is_signed)
54
{
55
    after_n_cycles(0, [this, dividend, divisor, is_8_bit, is_signed] {
56
        this->dut.dividend = dividend;
57
        this->dut.divisor = divisor;
58
        this->dut.start = 1;
59
        this->dut.is_8_bit = is_8_bit;
60
        this->dut.is_signed = is_signed;
61
        after_n_cycles(1, [this] { this->dut.start = 0; });
62
    });
63
 
64
    for (int i = 0; i < 100; ++i) {
65
        cycle();
66
        if (!done)
67
            continue;
68
        if (this->dut.error)
69
            throw DivideError("error");
70
        return;
71
    }
72
 
73
    FAIL() << "Execution timeout";
74
}
75
 
76
template <typename T1, typename T2>
77
struct DivTest {
78
    T1 v1;
79
    T2 v2;
80
    T2 quotient;
81
    T2 remainder;
82
    bool expect_error;
83
};
84
 
85
using Div8Params = struct DivTest<uint16_t, uint8_t>;
86
using Div16Params = struct DivTest<uint32_t, uint16_t>;
87
using IDiv8Params = struct DivTest<int16_t, int8_t>;
88
using IDiv16Params = struct DivTest<int32_t, int16_t>;
89
 
90
class DivTests16 : public DividerTestbench,
91
                   public ::testing::WithParamInterface<Div16Params>
92
{
93
};
94
TEST_P(DivTests16, Result)
95
{
96
    auto p = GetParam();
97
 
98
    if (p.expect_error) {
99
        EXPECT_THROW(divide(p.v1, p.v2, false, false), DivideError);
100
    } else {
101
        divide(p.v1, p.v2, false, false);
102
        EXPECT_EQ(quotient, p.quotient);
103
        EXPECT_EQ(remainder, p.remainder);
104
    }
105
 
106
    cycle(3);
107
}
108
INSTANTIATE_TEST_CASE_P(
109
    Div,
110
    DivTests16,
111
    ::testing::Values(Div16Params{100, 20, 5, 0, false},
112
                      Div16Params{500, 250, 2, 0, false},
113
                      Div16Params{10, 3, 3, 1, false},
114
                      Div16Params{128000, 10, 12800, 0, false},
115
                      Div16Params{130000, 32500, 4, 0, false},
116
                      Div16Params{0xffff, 1, 0xffff, 0, false},
117
                      // Divide by zero
118
                      Div16Params{130000, 0, 0, 0, true},
119
                      // Destination overflow
120
                      Div16Params{0x10000, 1, 0, 0, true}));
121
 
122
class DivTests8 : public DividerTestbench,
123
                  public ::testing::WithParamInterface<Div8Params>
124
{
125
};
126
TEST_P(DivTests8, Result)
127
{
128
    auto p = GetParam();
129
 
130
    if (p.expect_error) {
131
        EXPECT_THROW(divide(p.v1, p.v2, true, false), DivideError);
132
    } else {
133
        divide(p.v1, p.v2, true);
134
        EXPECT_EQ(quotient, p.quotient);
135
        EXPECT_EQ(remainder, p.remainder);
136
    }
137
 
138
    cycle(3);
139
}
140
INSTANTIATE_TEST_CASE_P(Div,
141
                        DivTests8,
142
                        ::testing::Values(Div8Params{100, 20, 5, 0, false},
143
                                          Div8Params{500, 250, 2, 0, false},
144
                                          Div8Params{10, 3, 3, 1, false},
145
                                          Div8Params{0xff, 1, 0xff, 0, false},
146
                                          // Divide by zero
147
                                          Div8Params{1, 0, 0, 0, true},
148
                                          // Destination overflow
149
                                          Div8Params{0x100, 1, 0, 0, true}));
150
 
151
TEST_F(DividerTestbench, MSBsIgnored8Bit)
152
{
153
    ASSERT_NO_THROW(divide(0x10008000, 0xff, true, false));
154
 
155
    EXPECT_EQ(quotient & 0xff, 0x80);
156
    EXPECT_EQ(remainder & 0xff, 0x80);
157
}
158
 
159
class IDivTests16 : public DividerTestbench,
160
                    public ::testing::WithParamInterface<IDiv16Params>
161
{
162
};
163
TEST_P(IDivTests16, Result)
164
{
165
    auto p = GetParam();
166
 
167
    if (p.expect_error) {
168
        EXPECT_THROW(divide(p.v1, p.v2, false, true), DivideError);
169
    } else {
170
        divide(p.v1, p.v2, false, true);
171
        EXPECT_EQ(static_cast<int16_t>(quotient), p.quotient);
172
        EXPECT_EQ(static_cast<int16_t>(remainder), p.remainder);
173
    }
174
 
175
    cycle(3);
176
}
177
INSTANTIATE_TEST_CASE_P(
178
    IDiv,
179
    IDivTests16,
180
    ::testing::Values(IDiv16Params{10, 3, 3, 1, false},
181
                      IDiv16Params{10, -3, -3, 1, false},
182
                      IDiv16Params{-10, -3, 3, -1, false},
183
                      IDiv16Params{-10, 3, -3, -1, false},
184
                      IDiv16Params{-10, 0, 0, 0, true},
185
                      IDiv16Params{65534, 2, 32767, 0, false},
186
                      IDiv16Params{-65536, 2, -32768, 0, false},
187
                      // Positive integer overflow
188
                      IDiv16Params{65536, 2, 0, 0, true},
189
                      // Negative integer overflow
190
                      IDiv16Params{-65538, 2, 0, 0, true}));
191
 
192
class IDivTests8 : public DividerTestbench,
193
                   public ::testing::WithParamInterface<IDiv8Params>
194
{
195
};
196
TEST_P(IDivTests8, Result)
197
{
198
    auto p = GetParam();
199
 
200
    if (p.expect_error) {
201
        EXPECT_THROW(divide(p.v1, p.v2, true, true), DivideError);
202
    } else {
203
        divide(p.v1, p.v2, true, true);
204
        EXPECT_EQ(static_cast<int8_t>(quotient), p.quotient);
205
        EXPECT_EQ(static_cast<int8_t>(remainder), p.remainder);
206
    }
207
 
208
    cycle(3);
209
}
210
INSTANTIATE_TEST_CASE_P(IDiv,
211
                        IDivTests8,
212
                        ::testing::Values(IDiv8Params{10, 3, 3, 1, false},
213
                                          IDiv8Params{10, -3, -3, 1, false},
214
                                          IDiv8Params{-10, -3, 3, -1, false},
215
                                          IDiv8Params{-10, 3, -3, -1, false},
216
                                          // Divide by zero
217
                                          IDiv8Params{-10, 0, 0, 0, true},
218
                                          IDiv8Params{254, 2, 127, 0, false},
219
                                          IDiv8Params{-256, 2, -128, 0, false},
220
                                          // Positive integer overflow
221
                                          IDiv8Params{256, 2, 0, 0, true},
222
                                          // Negative integer overflow
223
                                          IDiv8Params{-258, 2, 0, 0, true}));

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.